Nell'esempio il metodo A e il metodo B sono metodi di istanza (al contrario dei metodi statici). Inserendo synchronized
un metodo di istanza significa che il thread deve acquisire il blocco (il "blocco intrinseco") sull'istanza dell'oggetto su cui viene chiamato il metodo prima che il thread possa iniziare l'esecuzione di qualsiasi codice in quel metodo.
Se hai due diversi metodi di istanza contrassegnati come sincronizzati e thread diversi chiamano questi metodi contemporaneamente sullo stesso oggetto, quei thread contenderanno lo stesso blocco. Una volta che un thread ottiene il blocco, tutti gli altri thread vengono esclusi da tutti i metodi di istanza sincronizzati su quell'oggetto.
Affinché i due metodi vengano eseguiti contemporaneamente, dovrebbero utilizzare blocchi diversi, in questo modo:
class A {
private final Object lockA = new Object();
private final Object lockB = new Object();
public void methodA() {
synchronized(lockA) {
//method A
}
}
public void methodB() {
synchronized(lockB) {
//method B
}
}
}
dove la sintassi del blocco sincronizzato consente di specificare un oggetto specifico di cui il thread in esecuzione deve acquisire il blocco intrinseco per accedere al blocco.
La cosa importante da capire è che anche se stiamo mettendo una parola chiave "sincronizzata" su singoli metodi, il concetto centrale è il blocco intrinseco dietro le quinte.
Ecco come il tutorial Java descrive la relazione:
La sincronizzazione si basa su un'entità interna nota come blocco intrinseco o blocco monitor. (Le specifiche API spesso si riferiscono a questa entità semplicemente come un "monitor".) I blocchi intrinsechi svolgono un ruolo in entrambi gli aspetti della sincronizzazione: imporre l'accesso esclusivo allo stato di un oggetto e stabilire relazioni che accadono prima che siano essenziali per la visibilità.
A ogni oggetto è associato un blocco intrinseco. Per convenzione, un thread che necessita di un accesso esclusivo e coerente ai campi di un oggetto deve acquisire il blocco intrinseco dell'oggetto prima di accedervi, quindi rilasciare il blocco intrinseco una volta terminato con essi. Si dice che un thread possiede il blocco intrinseco tra il momento in cui ha acquisito il blocco e rilasciato il blocco. Finché un thread possiede un blocco intrinseco, nessun altro thread può acquisire lo stesso blocco. L'altro thread si bloccherà quando tenta di acquisire il blocco.
Lo scopo del blocco è proteggere i dati condivisi. Si utilizzerebbero blocchi separati come mostrato nel codice di esempio sopra solo se ciascun blocco proteggesse membri di dati diversi.