La parola chiave synchronized è stata introdotta in Java con il supporto per il multithreading per garantire accesso esclusivo a blocchi di codice o metodi da thread diversi. Storicamente, questo è la risposta di Java ai classici problemi di race condition e inconsistenza dei dati, che si verificano quando si accede contemporaneamente a dati condivisi da più thread.
Problema nell'uso del multithreading — garantire "atomicità" delle operazioni e prevenire modifiche contraddittorie degli stati degli oggetti. Un uso improprio di synchronized può portare a deadlock, degrado delle prestazioni o addirittura assenza di sincronizzazione in caso di scelta errata dell'oggetto monitor.
Soluzione — utilizzare la parola chiave synchronized per metodi o blocchi di codice dove è necessario garantire che solo un thread alla volta possa eseguire quella porzione. È importante scegliere attentamente l'oggetto di sincronizzazione, evitare sezioni critiche lunghe e, per compiti più complessi, utilizzare classi speciali del pacchetto java.util.concurrent.
Esempio di codice:
public class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } } // Sincronizzazione solo su parte del codice su un oggetto diverso: private final Object lock = new Object(); public void complexIncrement() { synchronized (lock) { // sezione critica count++; } }
Caratteristiche chiave:
Qual è la differenza tra un metodo synchronized e un blocco synchronized?
Il metodo sincronizzato blocca il "monitor" dell'oggetto (o della classe, se il metodo è statico), il blocco sincronizzato consente di specificare esplicitamente l'oggetto di monitoraggio, offrendo maggiore flessibilità.
Cosa succede se si sincronizzano diversi metodi nello stesso oggetto?
Se entrambi i metodi sono contrassegnati come synchronized (non statici), entrambi utilizzano come monitor lo stesso oggetto (this). Un thread non può accedere a nessuno dei metodi finché l'altro è occupato in uno di essi.
È possibile sincronizzare metodi statici e normali? Come si sbloccano reciprocamene?
I metodi statici utilizzano il monitor della classe stessa (oggetto Class), i metodi normali utilizzano l'oggetto dell'istanza. Di conseguenza, un metodo statico synchronized e un metodo normale synchronized non si bloccano a vicenda.
Un programmatore sincronizza metodi di oggetti diversi, ma utilizza ovunque lo stesso String come monitor. Di conseguenza, si verifica un rallentamento e "deadlock casuali" a causa del riutilizzo di stringhe dal pool.
Pro:
Contro:
Sincronizzazione su un oggetto privato finale, creato solo all'interno della classe (private final Object lock), e le sezioni critiche sono minime in termini di tempo.
Pro:
Contro: