Zámky

Může se stát, že několik úloh v systému potřebuje získat přístup a manipulovat se stejným objektem. ILock definuje protokol pro udělení výhradního přístupu ke sdílenému objektu. Když nějaká úloha potřebuje přístup ke sdílenému objektu, získá pro takový objekt tzv. zámek neboli uzamčení. Po skončení manipulace s objektem tento zámek uvolní.

Zámek se obvykle vytváří, když je sdílený objekt vytvořen nebo se do něj snaží modul plug-in získat přístup poprvé. Znamená to, že kód, který odkazuje na sdílený objekt, zároveň odkazuje i na jeho zámek. Začneme vytvořením zámku myLock, který použijeme pro řízení přístupu k objektu myObject:

   ...
   myObject = initializeImportantObject();
   IJobManager jobMan = Platform.getJobManager();
   myLock = jobMan.newLock();
   ...

Robustní implementaci zámku ILock poskytuje platforma. Správce úloh poskytuje klientům k použití instance tohoto zámku. Tyto známky o sobě navzájem "vědí" a dokáží zabránit vzniku kruhového zablokování. (Tuto větu si za okamžik blíže vysvětlíme.)

Kdykoli kód v úloze potřebuje přístup do objektu myObject, musí si nejprve opatřit příslušný zámek. Následující úsek kódu znázorňuje běžný způsob práce se zámkem:

...
// Potřebuji manipulovat s objektem myObject, a proto si nejdříve opatřím jeho zámek.
  try {
	myLock.acquire();
	updateState(myObject);  // manipulovat s objektem
   } finally {
	lock.release();
}
...

Metoda acquire() vrátí kladnou odezvu teprve tehdy, až bude možno volající úloze udělit výhradní přístup k zámku. Jinými slovy, pokud jiná úloha již získala požadovaný zámek, potom tento kód bude blokován až do okamžiku, kdy bude zámek opět k dispozici. Všimněte si, že kód, který získá zámek a manipuluje s objektem myObject, je zabalen v bloku try, takže je možno zámek uvolnit, pokud při práci s objektem dojde k jakýmkoli výjimkám.

Vypadá to docela jednoduše, viďte? Naštěstí je používání zámků dost logické. Jsou také opakovaně přístupné, což znamená, že se nemusíte obávat, že by vaše úloha mohla mít problémy získat přístup ke stejnému zámku vícekrát. Každý zámek sleduje počet získání a uvolnění v každém procesu a uvolní se z určité úlohy pouze tehdy, když se počet uvolnění rovná počtu získání.

Zablokování

Již dříve jsme si všimli, že zámky poskytované správcem úloh se navzájem sledují a dokáží zabránit kruhovému zablokování. Abychom pochopili, jak může dojít ke vzniku zablokování, podívejme se nyní na jednoduchý scénář. Předpokládejme, že úloha"Job A" získá zámek "Lock A" a následně se pokusí získat zámek "Lock B." Mezitím je zámek "Lock B" v držení úlohy "Job B", která je nyní blokována čekáním na zámek "Lock A." Tento druh zablokování ukazuje, že jeho příčinou je chybný návrh způsobu používání zámků jednotlivými úlohami. I když tomuto jednoduchému případu zablokování se lze snadno vyhnout, pravděpodobnost náhodného vzniku zablokování značně vzrůstá při zvyšování počtu úloh a zámků ve vašem návrhu.

Naštěstí vám platforma pomůže zablokování nalézt. Když správce úloh zjistí zablokování, vytiskne diagnostické informace do protokolu s popisem podmínek, za kterých k zablokování došlo. Poté zablokování přeruší tím, že přístup k zámkům, které má v držení zablokovaná úloha, dočasně poskytne jiným úlohám, jež na tyto zámky čekají. Je nezbytné pečlivě otestovat jakoukoli implementaci obsahující více zámků a odstranit veškeré podmínky, jež by mohly vést ke vzniku zablokování a jež platforma uvádí v příslušném protokolu.