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:
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; } }
enum EnumSingleton { INSTANCE; // metodi }
private Object readResolve() { return getInstance(); }
È 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
volatileal 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.