Mi chiedo quale di questi sia meglio in pratica e perché?
Ho scoperto che Lock
e Condition
(e altre nuove concurrent
classi) sono solo altri strumenti per la cassetta degli attrezzi. Potevo fare quasi tutto il necessario con il mio vecchio martello da carpentiere (la synchronized
parola chiave), ma era scomodo da usare in alcune situazioni. Molte di quelle situazioni imbarazzanti sono diventate molto più semplici una volta che ho aggiunto più strumenti alla mia cassetta degli attrezzi: un martello di gomma, un martello a sfera, un palanchino e alcuni punzoni per unghie. Tuttavia , il mio vecchio martello da carpentiere vede ancora la sua quota di utilizzo.
Non penso che uno sia davvero "migliore" dell'altro, ma piuttosto ognuno è più adatto a problemi diversi. In poche parole, il modello semplice e la natura orientata all'ambito synchronized
mi aiutano a proteggermi dai bug nel mio codice, ma quegli stessi vantaggi sono talvolta ostacoli in scenari più complessi. Sono questi scenari più complessi che il pacchetto simultaneo è stato creato per aiutare a risolvere. Ma l'utilizzo di questi costrutti di livello superiore richiede una gestione più esplicita e attenta del codice.
===
Penso che JavaDoc faccia un buon lavoro nel descrivere la distinzione tra Lock
e synchronized
(l'enfasi è mia):
Le implementazioni di blocco forniscono operazioni di blocco più estese di quelle ottenibili utilizzando metodi e istruzioni sincronizzati. Consentono una strutturazione più flessibile , possono avere proprietà piuttosto diverse e possono supportare più oggetti Condizione associati .
...
L'uso di metodi o istruzioni sincronizzati fornisce l'accesso al blocco monitor implicito associato a ogni oggetto, ma impone che tutti i blocchi e le acquisizioni avvengano in modo strutturato a blocchi : quando vengono acquisiti più blocchi , devono essere rilasciati nell'ordine opposto , e tutti i blocchi devono essere rilasciati nello stesso ambito lessicale in cui sono stati acquisiti .
Mentre il meccanismo di scoping per metodi e istruzioni sincronizzati semplifica notevolmente la programmazione con i blocchi monitor e aiuta a evitare molti errori di programmazione comuni che coinvolgono i blocchi, ci sono occasioni in cui è necessario lavorare con i blocchi in modo più flessibile. Ad esempio, * * alcuni algoritmi * per attraversare strutture di dati accessibili contemporaneamente richiedono l'uso di "hand-over-hand" o "chain lock" : acquisisci il blocco del nodo A, quindi il nodo B, quindi rilascia A e acquisisci C, quindi rilasciare B e acquisire D e così via. Le implementazioni dell'interfaccia Lock consentono l'utilizzo di tali tecniche consentendo l'acquisizione e il rilascio di un lock in diversi ambiti econsentendo l'acquisizione e il rilascio di più blocchi in qualsiasi ordine .
Con questa maggiore flessibilità derivano ulteriori responsabilità . L' assenza di blocchi strutturati a blocchi rimuove il rilascio automatico dei blocchi che si verifica con metodi e istruzioni sincronizzati. Nella maggior parte dei casi, si dovrebbe usare il seguente linguaggio:
...
Quando si verificano il blocco e lo sblocco in diversi ambiti , è necessario assicurarsi che tutto il codice che viene eseguito mentre il blocco viene tenuto sia protetto da try-finally o try-catch per garantire che il blocco venga rilasciato quando necessario.
Le implementazioni di blocco forniscono funzionalità aggiuntive rispetto all'uso di metodi e istruzioni sincronizzati fornendo un tentativo non bloccante di acquisire un blocco (tryLock ()), un tentativo di acquisire il blocco che può essere interrotto (lockInterruptibly () e un tentativo di acquisizione il blocco che può timeout (tryLock (long, TimeUnit)).
...