In primo luogo, perché dovresti voler caricare pigro un singleton? In produzione, in tipicamente desidera caricare avidamente tutte tuoi single così si cattura errori presto e prendere qualsiasi prestazione ha colpito fino fronte, ma nei test e durante lo sviluppo, si desidera solo caricare ciò è assolutamente così bisogno di non a tempo di scarto.
Prima di Java 1.5, ho caricato in modo pigro singletons utilizzando pianura vecchio sincronizzazione, semplice ma efficace:
static Singleton instance;
public static synchronized Singleton getInstance() {
if (instance == null)
instance == new Singleton();
return instance;
}
Le modifiche apportate al modello di memoria di 1.5 abilitato il famigerato ricontrollato Locking (DCL) idioma . Per implementare DCL, si controlla un campo volatile
nel percorso comune e sincronizzare solo quando necessario, :
static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null)
instance == new Singleton();
}
}
return instance;
}
Ma volatile
non è che molto più veloce di quanto synchronized
, synchronized
è piuttosto veloce al giorno d'oggi, e DCL richiede altro codice, quindi anche dopo 1.5 è uscito, Ho continuato a utilizzare la semplice sincronizzazione vecchia.
Immaginate la mia sorpresa oggi, quando Jeremy Manson mi indicò la Initialization on Demand Holder (IODH) idiom che richiede molto poco codice e ha a zero spese generali sincronizzazione. Zero, come in ancora più veloce di volatile
. IODH richiede lo stesso numero di righe del codice come semplice sincronizzazione precedente e è più veloce di DCL!
IODH utilizza l'inizializzazione classe pigra . La JVM non eseguirà lo inizializzatore statico di una classe finché non si tocca effettivamente qualcosa nella classe con lo . Questo vale anche per le classi nidificate statiche, . Nel seguente esempio, il JLS guarantees la JVM non verrà inizializzato instance
fino a quando qualcuno chiamate getInstance()
:
static class SingletonHolder {
static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
[...]
Aggiornamento: di credito che è di Cesare, Effective Java (diritti d'autore 2001) dettagliato questo modello sotto la voce 48. Va avanti a sottolineare che è ancora necessario utilizzare la sincronizzazione o DCL in contesti non statici.
Ho anche acceso movimentazione Singleton in mio quadro dalla sincronizzazione di DCL e vide un'altra performance incremento del 10% (rispetto a prima ho iniziato utilizzando la riflessione veloce di cglib). Ho solo usato un thread nel mio micro-benchmark, così la spinta alla concorrenza potrebbe essere ancora maggiore dato che ho sostituito un serratura fortemente sostenuto con un relativamente fine accesso grana campo volatili .
Nota che Joshua Bloch raccomanda ora (dal Effective Java, 2a ed) per implementare single con un unico elemento enum
come sottolineato da Jonik.
Nel secondo caso, dove stai inizializzando staticamente 'singletonObject', puoi (e dovresti) renderlo' final' pure, per evitare modifiche accidentali. (Tendo a preferire anche l'inizializzazione statica, per questo motivo.) – Wyzard