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:

    .
  1. getInstance() è non sincronizzato, quindi dopo l'istanza è inizializzato non vi è alcun costo per la sincronizzazione
  2. createInstance() è sincronizzato

    Allora, la domanda è: Questo codice ha problemi?È legale e sempre cabina di thread?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top