2013-03-19 16 views
6

mi sono imbattuto in un certo codice, in cui lo sviluppatore è costantemente controllando se il Singleton è nullo due volte con un nidificato se - come nel codice qui sotto:Java: c'è qualche motivo per verificare se un singleton è nullo due volte?

private static processManager singleton = null; 

...

public synchronized static processManager getInsatnce() throws Exception { 

    if(singleton == null) { 
     if(singleton == null){ 
      singleton = new processManager(); 
     } 
    } 
    return singleton 
} 

I non riesco a vedere alcun motivo per cui questo potrebbe essere, ma ci sono numerose istanze nel codice, quindi ho pensato che ci potesse essere un motivo?

+6

Sembra un tentativo fallito di blocco a due fasi. Questo avrebbe potuto avere senso se l'istruzione 'if' più interna fosse in un blocco' sincronizzato'. – toniedzwiedz

+0

Sì, sto guardando la risposta di Marko. Interessante! – Sanchit

+0

http://en.wikipedia.org/wiki/Double-checked_locking? – mbatchkarov

risposta

15

Il tuo codice non dimostra correttamente il caso. Ciò deriva dal ricontrollato idioma, dove non ha senso:

// Double-check idiom for lazy initialization of instance fields. 
private volatile FieldType field; 
FieldType getField() { 
    FieldType result = field; 
    if (result == null) { // First check (no locking) 
     synchronized(this) { 
      result = field; 
      if (result == null) // Second check (with locking) 
       field = result = computeFieldValue(); 
     } 
    } 
    return result; 
} 

Leggi su di esso over here.

Fare attenzione a notare che questo idioma è una buona scelta solo per i campi istanza. Nella tua domanda si dispone di un campo static, per qual caso un linguaggio molto più semplice è la scelta primaria: il pigro initialion classe titolare idioma:

// Lazy initialization holder class idiom for static fields 
private static class FieldHolder { 
    static final FieldType field = computeFieldValue(); 
} 
static FieldType getField() { return FieldHolder.field; } 
0

Questo non fa alcuna sence a meno che il Singleton è una proprietà che crea l'istanza nel getter, ma anche in questo caso ciò non avrebbe senso, quindi il resto del codice sarebbe irraggiungibile.

2

Penso che ti riferisci a Double Checked Locking. Questo modello consente di evitare la sincronizzazione quando non è necessaria.

codice Si dovrebbe essere

private static volatile ProcessManager singleton = null; 

public static ProcessManager getInstance() throws Exception { 

    if (singleton == null) { 
     synchronized (MyClass.class) { 
      if (singleton == null) { 
       singleton = new ProcessManager(); 
      } 
     } 
    } 
    return singleton; 
} 

Così si vede che solo la sincronizzazione quando abbiamo verificato che il Singleton non è nullo, abbiamo poi ricontrolleremo in caso qualcuno ha già iniziato a costruirlo. Non che ciò funzioni, il singleton deve esserevolatile. Here è un articolo che spiega il sottile problema che si pone se si dimentica lo volatile.

Nel tuo caso, dove il metodo è sincronizzato, hai ragione. Non ha senso controllare due volte.

2

È un tentativo fallito di raggiungere Double Checked Locking Idiom. Il primo controllo null è per vedere se l'istanza è già stata creata e se è not null restituire semplicemente l'istanza già creata.

Ma il controllo condizione è una situazione arrivo poi atto ed è non thread-safe, per cui v'è una possibilità che due o più fili vedrà il valore come null e creare due istanze di singleton e questo è doubleton o forse ManyTon.

Quindi si utilizza synchronized in modo che solo un thread entri in quel blocco e venga creata solo una singola istanza.

+0

Ottima spiegazione su Double Checked Locking Idiom. – Deepak

+0

Quindi, poiché il metodo è sincronizzato, non è presumibilmente necessario utilizzare il doppio blocco controllato? –

+0

Mantenere il metodo singleton crea un evento prima della relazione e quindi è giusto avere un solo controllo null. NOTA: questo metodo si comporta male perché blocca la classe. Quindi è meglio non mantenere sincronizzato il metodo ma usare la tecnica che è già stata menzionata in altre risposte. –

0

La tecnica è denominata doppio controllo.

Il codice incollato, tuttavia, non è corretto. Hai ragione, non ha senso ricontrollare il valore null in questo modo. Direi che corretta esecuzione del doppio controllo segue:

private static volatile ProcessManager instance = null; 

public static ProcessManager getInstance() { 
    if (instance == null) { 
     synchronized(ProcessManager.class) { 
     if (instance == null) { 
      instance = new ProcessManager(); 
     } 
     } 
    } 
    return instance; 
} 

noti che secondo controllo nullo è sincronizzato sull'oggetto ProcessManager.class. È necessario perché il metodo getInstance() è statico.

+1

Questo mi sembra danneggiato a meno che l'istanza non sia volatile: la prima lettura dell'istanza 'if (instance == null)' non è sincronizzata. – assylias

+0

Sì, hai ragione. –

Problemi correlati