Sì, è necessario. Esistono diversi metodi che è possibile utilizzare per ottenere la sicurezza dei thread con l'inizializzazione lenta:
Sincronizzazione draconiana:
private static YourObject instance;
public static synchronized YourObject getInstance() {
if (instance == null) {
instance = new YourObject();
}
return instance;
}
Questa soluzione richiede che ogni thread sia sincronizzato quando in realtà solo i primi devono esserlo.
Doppio controllo della sincronizzazione :
private static final Object lock = new Object();
private static volatile YourObject instance;
public static YourObject getInstance() {
YourObject r = instance;
if (r == null) {
synchronized (lock) { // While we were waiting for the lock, another
r = instance; // thread may have instantiated the object.
if (r == null) {
r = new YourObject();
instance = r;
}
}
}
return r;
}
Questa soluzione garantisce che solo i primi pochi thread che tentano di acquisire il singleton debbano passare attraverso il processo di acquisizione del blocco.
Inizializzazione su richiesta :
private static class InstanceHolder {
private static final YourObject instance = new YourObject();
}
public static YourObject getInstance() {
return InstanceHolder.instance;
}
Questa soluzione sfrutta le garanzie del modello di memoria Java sull'inizializzazione della classe per garantire la sicurezza dei thread. Ogni classe può essere caricata una sola volta e verrà caricata solo quando necessario. Ciò significa che la prima volta che getInstance
viene chiamata, InstanceHolder
verrà caricata e instance
verrà creata, e poiché questo è controllato da ClassLoader
s, non è necessaria alcuna sincronizzazione aggiuntiva.