ProgrammazioneSviluppatore Backend

Descrivi come funziona la parola chiave synchronized in Java, in quali casi usarla e a quali problemi può portare un suo uso improprio?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

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:

  • synchronized blocca l'accesso al codice per altri thread sul "monitor" scelto
  • È possibile sincronizzare interi metodi o solo singoli blocchi
  • La sincronizzazione è uno strumento potente, ma rischioso (deadlock, prestazioni)

Domande trabocchetto.

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.

Errori tipici e anti-pattern

  • Sincronizzazione su un oggetto errato (ad esempio, su String o oggetti da un pool)
  • Sezioni critiche troppo lunghe o poco chiare, che portano a degrado delle prestazioni
  • Attesa ciclica o deadlock
  • Abuso di synchronized invece di utilizzare moderne alternative dal pacchetto java.util.concurrent

Esempio dalla vita reale

Caso negativo

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:

  • Codice breve, scrittura più veloce.

Contro:

  • Alto rischio di deadlock
  • Difficoltà nella debug
  • Forte abbassamento delle prestazioni

Caso positivo

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:

  • Garanzia di un comportamento corretto
  • Minimi sovraccosti
  • Buona leggibilità e manutenibilità

Contro:

  • Richiede disciplina ed esperienza
  • Non sempre è ovvio per i programmatori principianti