ProgrammazioneSviluppatore backend Java

Как в Java реализовать паттерн Singleton с учётом многопоточности и сериализации? Какие существуют нюансы реализации?

Supera i colloqui con l'assistente IA Hintsage

Risposta

Il classico Singleton garantisce la creazione di un solo oggetto. In Java ci sono diversi modi per implementarlo, ma considerando la multithreading e la serializzazione, è necessario tenere presente alcuni dettagli:

  1. Implementazione Thread-safe (Double-checked Locking): Spesso utilizzata per l'inizializzazione pigra.
public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
  1. Enum Singleton: Il modo migliore in termini di protezione contro la serializzazione, la reflection e la multithread.
enum EnumSingleton { INSTANCE; // metodi }
  1. Problemi con la serializzazione: Un normale Singleton dopo la serializzazione/deserializzazione potrebbe perdere l'unicità dell'istanza. Per un funzionamento corretto, è necessario aggiungere il metodo readResolve():
private Object readResolve() { return getInstance(); }

Domanda insidiosa

È sufficiente utilizzare il metodo synchronized getInstance() per un Singleton thread-safe?

Risposta: Sì, ma questo approccio porta a una diminuzione delle prestazioni poiché synchronized viene chiamato a ogni accesso a getInstance. Più efficace è Double-checked Locking + volatile per instance, o l'uso di Enum per l'implementazione di Singleton.

Esempio di codice inefficace:

public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }

Storia

Nella sistema finanziario, durante l'implementazione del singleton, si è dimenticato di aggiungere volatile al riferimento instance nel double-checked locking. Di conseguenza, ad alti carichi si verificavano casi casuali di creazione di due istanze della classe, causando inconsistenza nei report.


Storia

Nella libreria di logging, abbiamo implementato Singleton tramite un oggetto statico privato, ma durante la serializzazione e la successiva deserializzazione (ad esempio, in un contesto cluster) sono emerse più istanze. Il problema è stato risolto aggiungendo readResolve().


Storia

Nella sistema di analisi, lo sviluppatore ha implementato un Singleton thread-safe tramite il metodo synchronized getInstance(). In un sistema ad alta richiesta, durante il picco, si è verificato un brusco calo delle prestazioni, si è scoperto che le chiamate a getInstance() (migliaia di volte al secondo) bloccavano l'una l'altra a causa di una sincronizzazione non necessaria, anche se l'inizializzazione è necessaria solo una volta.