En av de store utfordringene i et komplekst system er å oppnå operativ funksjon samtidig som det utføres oppgaver. Denne utfordringen er enda større i et omfattende system når komponenter som ikke er utformet for å kjøre sammen, deler samme ressurs. Pakken org.eclipse.core.runtime.jobs håndterer denne utfordringen ved å oppgi infrastruktur for planlegging, utføring og styring av operasjoner som kjøres samtidig. Infrastrukturen er basert på bruken av jobber for å representere en arbeidsenhet som kan kjøres asynkront.
class TrivialJob extends Job { public TrivialJob() { super("Trivial Job"); } public IStatus run(IProgressMonitor monitor) { System.out.println("This is a job"); return Status.OK_STATUS; } }I snutten nedenfor ser du hvordan jobben opprettes og planlegges:
TrivialJob job = new TrivialJob(); System.out.println("About to schedule a job"); job.schedule(); System.out.println("Finished scheduling a job");Programmets utdata er tidsavhengig. Det betyr at det er umulig å sikkert vite når jobbens run-metode utføres i henhold til tråden som opprettet og planla jobben. Utdataene er enten:
About to schedule a job This is a job Finished scheduling a jobeller:
About to schedule a job Finished scheduling a job This is a job
Hvis du vil forsikre deg om at en jobb er fullført før du fortsetter, kan du bruke join()-metoden. Denne metoden blokkerer kalleren til jobben er fullført eller til kalltråden er avbrutt. Vi skal nå skrive om snutten ovenfor på en mer deterministisk måte:
TrivialJob job = new TrivialJob(); System.out.println("About to schedule a job"); job.schedule(); job.join(); if (job.getResult().isOk()) System.out.println("Job completed with success"); else System.out.println("Job did not complete successfully");Forutsatt at join()-kallet ikke avbrytes, returnerer denne metoden garantert følgende resultat:
About to schedule a job This is a job Job completed with success
Det er vanligvis ikke lurt å sammenføye en jobb like etter at den er planlagt, siden du da ikke kan dra nytte av samtidighet. Det er da bedre å utføre arbeidet fra jobbens kjøremetode direkte i kalltråden. Vi kommer tilbake med noen eksempler på hvor det er mest hensiktsmessig med sammenføyninger.
Den siste snutten bruker også jobbresultatet. Resultatet er IStatus-objektet som returneres fra jobbens run()-metode. Du kan bruke dette resultatet til å sende nødvendige objekter tilbake fra jobbens kjøremetode. Resultatet kan også brukes til å angi feil (ved å returnere en IStatus med alvorsgraden IStatus.ERROR) eller avbrudd (IStatus.CANCEL).
Vi har sett hvordan vi planlegger en jobb og venter på at den skal fullføres, men det er mange andre ting du kan gjøre med en jobb. Hvis du planlegger en jobb og senere finner ut at du ikke trenger den, kan jobben stoppes ved hjelp av cancel()-metoden. Hvis jobben ikke har startet å kjøre når den avbrytes, fjernes jobben umiddelbart og vil ikke bli kjørt. Hvis jobben derimot allerede har startet å kjøre, avgjør jobben om det skal reageres på avbruddet. Når du forsøker å avbryte en jobb, kan du bruke metoden join() mens du venter på at den skal bli ferdig. Nedenfor ser du et vanlig idiom for jobbavbrudd og venting på at en jobb skal bli ferdig før videre behandling påbegynnes:
if (!job.cancel()) job.join();
Hvis avbruddet ikke inntreffer øyeblikkelig, returnerer cancel() "false" og kalleren bruker join() til å vente på at jobben skal bli avbrutt.
Metoden sleep() er en noe mindre drastisk metode. Hvis jobben ikke kjører, vil denne metoden sette jobben på venting på ubestemt tid. Plattformen vil fortsatt huske jobben, og et wakeUp()-kall legger til jobben i ventekøen der den omsider vil bli utført.
En jobb har flere statuser i løpet av levetiden. Foruten å kunne manipuleres gjennom programmeringsgrensesnittet, for eksempel med cancel() og sleep(), endres også statusen når plattformen kjører og fullfører jobben. En jobb kan ha følgende statuser:
En jobb kan settes i sovetid hvis den har statusen VENTER. Hvis en jobb som er i sovetid gjøres aktiv igjen, får den på nytt statusen VENTER. Hvis en jobb avbrytes, får den statusen INGEN.
Hvis plugin-modulen trenger statusen til en bestemt jobb, er det mulig å registrere en jobbendringslytter som varsles etter hvert som jobben endrer seg. Dette er nyttig når du vil se på fremdriften eller rapportere om en jobb.
Jobbmetoden addJobChangeListener kan brukes til å registrere en lytter i en bestemt jobb. IJobChangeListener definerer en protokoll som håndterer statusendringer i en jobb:
I alle disse tilfellene får lytteren oppgitt en IJobChangeEvent som angir hvilken jobb som er i ferd med å endre status, og dessuten hvilken status den har når den er fullført (hvis den er ferdig).
Merk: Jobber definerer også metoden getState() for å innhente en (relativt) oppdatert jobbstatus. Det er imidlertid ikke alltid mulig å stole på dette resultatet siden jobber kjøres i ulike tråder og kan endre status i det kallet returneres. Jobbendringslyttere er den anbefalte metoden for å finne statusendringer i en jobb.
IJobManager definerer en protokoll for arbeid med alle jobber i systemet. Plugin-moduler som viser fremdrift eller på annen måte arbeider med jobbinfrastrukturen, kan bruke IJobManager til å utføre oppgaver som å deaktivere alle jobber i systemet, finne ut hvilken jobb som kjøres eller motta tilbakemelding om fremdrift for en bestemt jobb. Plattformens jobbstyrer kan innhentes via programmeringsgrensesnittet for Platform:
IJobManager jobMan = Platform.getJobManager();
Plugin-moduler som trenger statusen for alle jobber i systemet, kan registrere en jobbendringslytter på jobbstyreren i stedet for å registrere lyttere i mange enkeltstående jobber.
Av og til er det enklere for en plugin-modul å arbeide med en gruppe beslektede jobber som en enhet. Dette gjøres ved å bruke jobbfamilier. En jobb deklarerer at den tilhører en bestemt familie ved å overstyre metoden belongsTo:
public static final String MY_FAMILY = "myJobFamily"; ... class FamilyJob extends Job { ... public boolean belongsTo(Object family) { return family == MY_FAMILY; } }Protokollen IJobManager kan brukes til å avbryte, sammenføye, gjøre jobben sovende eller finne alle jobber i en familie:
IJobManager jobMan = Platform.getJobManager(); jobMan.cancel(MY_FAMILY); jobMan.join(MY_FAMILY, null);
Siden jobbfamiliene representeres gjennom vilkårlige objekter, kan du lagre interessante statuser i selve jobbfamilien, og jobber kan dynamisk danne familieobjekter etter behov. Det er viktig å bruke familieobjekter som er unike for å unngå uheldig interaksjon med familier som er opprettet av andre plugin-moduler.
Med familier er det også enkelt å finne grupper av jobber. Metoden IJobManager.find(Object family) kan brukes til når som helst å finne forekomster av alle jobber som kjøres, venter og sover.