Een van de grootste uitdagingen van een complex systeem is om te kunnen blijven reageren terwijl de taken worden uitgevoerd. Deze uitdaging is zelfs nog groter voor uitbreidbare systemen waarin componenten die niet zijn geschreven om tegelijkertijd uitgevoerd te worden, toch dezelfde resources gebruiken. Het pakket org.eclipse.core.runtime.jobs speelt in op de uitdaging met zijn infrastructuur voor planning, uitvoering en beheer van gelijktijdig uitgevoerde bewerkingen. De infrastructuur is gebaseerd op het gebruik van jobs, werkeenheden die asynchroon uitgevoerd kunnen worden.
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; } }In het volgende codefragment wordt de job gemaakt en gepland:
TrivialJob job = new TrivialJob(); System.out.println("De job wordt nu gemaakt"); job.schedule(); System.out.println("De job is nu gepland");De uitvoer van dit programma is afhankelijk van de timing. Dat wil zeggen dat het nooit precies bekend is wanneer de methode run van een job wordt aangeroepen in relatie met de thread die de job heeft gemaakt en gepland. Voor de uitvoer bestaan de volgende mogelijkheden:
Op het punt een taak te plannen Dit is een job Gereed met plannen van een jobof:
Op het punt een taak te plannen Gereed met plannen van een job Dit is een job
Als u zeker wilt weten dat een job is voltooid voordat u verdergaat, kunt u de methode join() gebruiken. Deze methode blokkeert het aanroepende item tot de job is voltooid of tot de aanroepende thread wordt onderbroken. Een gerichtere versie van de bovenstaande code ziet er als volgt uit:
TrivialJob job = new TrivialJob(); System.out.println("De job wordt nu gemaakt"); job.schedule(); job.join(); if (job.getResult().isOk()) System.out.println("Job voltooid"); else System.out.println("Job niet voltooid");Aangenomen dat de aanroep van join() niet wordt onderbroken, levert deze methode gegarandeerd het volgende resultaat op:
Op het punt een taak te plannen Dit is een job Job voltooid
In het algemeen is het niet nuttig om een job direct na de planning samen te voegen, omdat u hiermee geen gelijktijdige uitvoering bewerkstelligt. In dit geval kunt u het werk van de methode run ook direct in de aanroepende thread doen. We kijken verderop naar een aantal voorbeelden waarin het gebruik van 'join' meer voor de hand ligt.
Het laatste codefragment maakt ook gebruik van het jobresultaat. Het resultaat is het object IStatus die wordt geretourneerd door de methode run() van de job. U kunt dit resultaat gebruiken om noodzakelijke objecten door te geven vanuit de methode run van de job. Het resultaat kan ook worden gebruikt om een fout aan te geven (door een IStatus met severity IStatus.ERROR te retourneren) of een annulering (IStatus.CANCEL).
U hebt gezien hoe u een job plant en wacht tot deze voltooid is, maar er zijn veel andere interessante bewerkingen voor jobs. Als u een job plant, maar deze niet meer nodig hebt, kunt u deze stoppen met de methode cancel(). Als u de job annuleert voordat deze is gestart, wordt de job direct verwijderd en niet uitgevoerd. Als de job wel is gestart, bepaalt deze zelf of hij reageert op een annuleringsopdracht. Als u probeert de job te annuleren, is het handig om voor het wachten de methode join() te gebruiken. Hier volgt een gebruikelijke code voor het annuleren van een taak en het wachten tot de job is voltooid:
if (!job.cancel()) job.join();
Als het annuleren niet direct van kracht wordt, retourneert cancel() 'false' en gebruikt het aanroepende item join() om te wachten tot de taak met succes is voltooid.
De methode sleep() is minder drastisch dan annulering. Als de job nog niet wordt uitgevoerd, zorgt de methode dat deze tot nader order wordt aangehouden. Het platform onthoudt het bestaan van de job en met een aanroep van de methode wakeUp() wordt deze toegevoegd aan de wachtrij, vanwaaruit hij uiteindelijk wordt uitgevoerd.
Een job heeft gedurende zijn levensloop verschillende statussen. De status kan niet alleen worden gewijzigd via een API als cancel() of sleep(), maar ook als het platform de job uitvoert en voltooit. Jobs kunnen de volgende status hebben:
Een job kan alleen niet-actief (sleeping) worden gemaakt als de huidige status WAITING is. Het activeren van een niet-actieve job geeft deze weer de status WAITING. Het annuleren van een job geeft de job de status NONE.
Als de plugin de status van een bepaalde job moet weten, kan deze een jobwijzigingslistener registreren die wordt gewaarschuwd als de job zich in een bepaald deel van zijn levenscyclus bevindt. Dit is nuttig voor het bijhouden van de voortgang of andere rapportage over de job.
De Job-methode addJobChangeListener kan worden gebruikt om een listener voor een bepaalde job te registreren. Met IJobChangeListener wordt een protocol gedefinieerd voor het reageren op statuswijzigingen van een job:
In al deze gevallen heeft de listener een IJobChangeEvent waarmee niet alleen de job met de statuswijziging wordt aangegeven, maar ook de status bij voltooiing.
Opmerking: In jobs wordt ook de methode getState() gedefinieerd voor het ophalen van de huidige status van de job. Het resultaat is echter niet altijd betrouwbaar, omdat jobs in verschillende threads worden uitgevoerd en een andere status kunnen hebben op het moment dat een reactie op de aanroep wordt ontvangen. Jobwijzigingslisteners worden aanbevolen als mechanisme voor het achterhalen van de statuswijzigingen in jobs.
Met IJobManager wordt een protocol gedefinieerd voor het werken met alle jobs in het systeem. Plugins die voortgangsweergave gebruiken of op een andere manier werken met de jobinfrastructuur, kunnen IJobManager gebruiken om verschillende taken uit te voeren, bijvoorbeeld het blokkeren van alle jobs in het systeem, het vaststellen welke job actief is of het ontvangen van voortgangsinformatie over een bepaalde job. De jobmanager van het platform kan worden opgehaald met de API Platform:
IJobManager jobMan = Platform.getJobManager();
Plugins die de status van alle jobs in het systeem willen weten, kunnen een jobwijzigingslistener voor de jobmanager registreren in plaats van listeners voor alle afzonderlijke jobs.
Soms is het sneller voor een plugin om met een groep gerelateerde jobs te werken als één eenheid. Dit kan worden gerealiseerd met jobfamilies. Een job declareert dat deze tot een bepaalde familie behoort door de methode belongsTo te overschrijven:
public static final String MY_FAMILY = "myJobFamily"; ... class FamilyJob extends Job { ... public boolean belongsTo(Object family) { return family == MY_FAMILY; } }U kunt het IJobManager-protocol gebruiken om alle jobs in een familie te annuleren, samen te voegen, inactief te maken of te zoeken:
IJobManager jobMan = Platform.getJobManager(); jobMan.cancel(MY_FAMILY); jobMan.join(MY_FAMILY, null);
Omdat jobfamilies worden aangegeven met willekeurige objecten, kunt u een belangrijke status opslaan in de familie zelf en jobs kunnen dynamisch de gewenste familieobjecten bouwen. Het is belangrijk dat u unieke of weinig voorkomende familieobjecten gebruikt om te voorkomen dat er interactie ontstaat met de families die in andere plugins zijn gemaakt.
Families zijn ook een handige manier om groepen jobs te zoeken. U kunt de methode IJobManager.find(Object family) gebruiken om instances te zoeken van alle taken die op een bepaald moment worden uitgevoerd, wachten of niet actief zijn.