La parola chiave sincronizzata è ancora richiesta (ignora la retrocompatibilità, sto pensando in termini di scrittura di nuovo codice, oggi) o dovremmo utilizzare tutte le funzionalità disponibili nei pacchetti Concurrent e Collection?
In effetti è necessario (in situazioni specifiche). Basta leggere attraverso Java Concurrency in Practice , è usato lì molte volte.
Ovviamente, dal momento che Java 5 di solito è in grado di risolvere felicemente i problemi usando (quasi) esclusivamente la toolbox java.util.concurrent
. E anche se abbiamo bisogno di scrivere le nostre classi thread-safe, synchronized
può spesso essere completamente sostituito da algoritmi non bloccanti come CAS . Tuttavia, CAS ha anche il suo prezzo, in quanto richiede un ragionamento, una sintonizzazione, ecc. Molto preciso e non è ben compreso da molti sviluppatori. Spesso non può fornire alcun vantaggio in termini di prestazioni, ma complica il codice. Quindi ci sono casi in cui è più semplice e più pulito usare solo un blocco synchronized
.
Si noti inoltre che i blocchi sono meno costosi di quelli usati in passato, mentre la JVM migliora con ogni versione. Molto tempo fa, questo prezzo è stato quello che ha impedito a molti sviluppatori di utilizzarli, ma non è più così strongmente giustificato (e anche se lo fosse, solo una misura concreta può dimostrare se il collo di bottiglia delle prestazioni è realmente in fase di blocco).
L'unico posto in cui synchronized
è ancora usato (almeno nel mio codice) scorre su elenchi sincronizzati. Javadocs per Collections.synchronizedCollection
dire che ogni volta che viene utilizzato un iteratore, l'intero blocco di codice che utilizza l'iteratore deve essere sincronizzato. Questo perché non stai facendo una singola operazione come add()
o remove()
, stai facendo più operazioni.
Esempio di codice da Javadocs
Collection c = Collections.synchronizedCollection(myCollection);
...
synchronized(c) {
Iterator i = c.iterator(); // Must be in the synchronized block
while (i.hasNext())
foo(i.next());
}
L'unico modo che conosco per aggirare questa limitazione è quello di accodare tutte le operazioni in un SingleThreadExecutor, ma questa è una soluzione molto costosa e arcaica.
Bene, dipende.
In pratica puoi risolvere qualsiasi problema usando i pacchetti simultanei e di raccolta.
Tuttavia, se vieni a scoprire che hai un collo di bottiglia solo nella sincronizzazione, probabilmente dovrai farlo manualmente e la parola chiave sincronizzata potrebbe essere solo l'amico di cui hai bisogno.
Suppongo che questo sia un problema improbabile da affrontare e, di solito, la riprogettazione della responsabilità del thread fornirà una soluzione più pulita rispetto all'ottimizzazione a mano, pur essendo sufficientemente veloce. Non sono riuscito a mettere le mani sulla fonte di quei pacchetti, ma non sarei sorpreso se usassero effettivamente sincronizzati per l'implementazione (ma il contrario non mi sorprenderebbe neanche).
Sì, il modificatore sincronizzato è molto vivo e richiesto. Certo, puoi usare Locks e altre cose dal pacchetto java.util.concurrent
, ma in molti casi questo è semplicemente un grosso overhead. Se si desidera assicurarsi che un determinato pezzo di codice venga eseguito esclusivamente, la parola chiave sincronizzata è il soluto più rapido e sicuro. Ci sono molte situazioni in cui ottenere un lucchetto, ottenerlo e rilasciarlo semplicemente non è necessario.
Quindi sì, per un buon programma multithread è effettivamente necessario l'uso della parola chiave sincronizzata.
Leggi altre domande sui tag java concurrency