Questo codice risolve il doppio problema di blocco controllato in Java?
-
12-11-2019 - |
Domanda
Questo codice risolve il doppio problema di blocco controllato in Java?
public class DBAccessService() {
private static DBAccessService INSTANCE;
private DBAccessService() {}
public static DBAccessService getInstance() {
if (INSTANCE != null) {
return INSTANCE;
}
return createInstance();
}
private static synchronized DBAccessService createInstance() {
if (INSTANCE != null) {
return INSTANCE;
}
DBAccessService instance = new DBAccessService();
INSTANCE = instance;
return INSTANCE;
}
}
.
Ci sono 2 aspetti per prestare attenzione:
- .
-
getInstance()
è non sincronizzato, quindi dopo l'istanza è inizializzato non vi è alcun costo per la sincronizzazione -
createInstance()
è sincronizzatoAllora, la domanda è: Questo codice ha problemi?È legale e sempre cabina di thread?
Soluzione
Per risolvere questa particolare domanda concorrenza Java in pratica (scritto dalla squadra che fondamentalmente ha scritto il java.util . Biblioteca .Concurrent) raccomanda il Inizio del titolare di inizializzazione pigro IDiom (pagina 348 nella mia copia, elenco 16.6, non 16.7)
@ThreadSafe
public class DBAccessServiceFactory {
private static class ResourceHolder {
public static DBAccessService INSTANCE = new DBAccessService();
}
public static DBAccessService getResource() {
return ResourceHolder.INSTANCE;
}
}
.
Questo è sempre legale e cassaforte del filo. Non sono un esperto, quindi non posso dire che questo è meglio del tuo codice. Tuttavia, dato che è il modello raccomandato da Doug Lea e Joshua Bloch, lo userei sempre sul codice tu o io abbiamo inventato, in quanto è così facile da sbagliare (come dimostrato dal numero di risposte errate a questa domanda ).
relativo al problema volatile che dicono:
.Le variazioni successive nel JMM (Java 5.0 e successive) hanno abilitato DCL di funzionare se la risorsa viene effettuata volatile ... tuttavia il pigro titolare di inizializzazione Idiom offre gli stessi vantaggi ed è più facile da capire.
Altri suggerimenti
È necessario dichiarare INSTANCE
come volatile
per il lavoro:
private static volatile DBAccessService INSTANCE;
.
Nota Lavora solo con Java 5 e successivamente.Vedi Il "blocco a doppio controllo è rotto" Dichiarazione .
In questo articolo è rivendicata "La registrazione controllata "non è un problema se si utilizza una classe Singleton separata:
public class DBAccessHelperSingleton {
public static DBAccessHelper instance = new DBAccessHelper();
}
.
ha lo stesso vantaggio: il campo non è istanziato prima di essere riferimenti la prima volta.
Come indicato in precedenza, se si desidera mantenere come se il volatile
è mancante nel caso in cui ti rivolga solo JDK>= 5.
Sembra bene. Se due thread Call GetInstance () e istanza non è initalizzato, solo un thread sarà in grado di procedere con Createinstance () e il secondo vedrà già quell'istanza non è nullo.
L'unica cosa è la parola chiave volatile
, ad esempio.Altrimenti Java può cache it.