2013-03-19 16 views
6

mam natknąć niektórych kodu, gdzie deweloper jest stale sprawdzając czy Singleton jest null dwukrotnie zagnieżdżone, gdy - jak w poniższym kodzie:Java - czy jest jakikolwiek powód, aby sprawdzić, czy singleton ma dwukrotnie wartość null?

private static processManager singleton = null; 

...

public synchronized static processManager getInsatnce() throws Exception { 

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

I nie widzę żadnego powodu, dlaczego by tak było, ale w kodzie jest wiele przykładów, więc pomyślałem, że może być jakiś powód?

+6

Wygląda na nieudaną próbę zablokowania dwufazowego. To mogło mieć sens, jeśli najbardziej wewnętrzna instrukcja "if" znajdowała się w bloku "zsynchronizowanym". – toniedzwiedz

+0

Tak, patrzę na odpowiedź Marko. Ciekawy! – Sanchit

+0

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

Odpowiedz

15

Twój kod nie demonstruje prawidłowo sprawy. Wynika to z podwójnie sprawdzone idiomu, gdzie to ma sens:

// 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; 
} 

przeczytać o tym over here.

Należy pamiętać, że ten idiom jest dobrym wyborem tylko dla pól instancji. W swoim pytaniu masz static pole, na którym to przypadku znacznie prostszy idiom jest podstawowym nastaw: leniwy initialion klasa posiadacz idiom:

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

To nie robi żadnej sence chyba że Singleton jest właściwością, która tworzy instancję w pobierającym, ale nawet wtedy nie miałoby to sensu, a reszta kodu byłaby nieosiągalna.

2

Myślę, że masz na myśli Double Checked Locking. Ten wzór pozwala uniknąć synchronizacji, gdy nie jest potrzebna.

kod powinien być

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; 
} 

Więc widzisz my tylko synchronizacja kiedy sprawdziliśmy, że Singleton nie jest null, my wtedy ponownie sprawdzić na wszelki wypadek, gdyby ktoś już zaczął go budować. Nie żeby to działało singleton musi byćvolatile. Here to artykuł, który wyjaśnia subtelny problem, który pojawia się, gdy zapomnisz volatile.

W twoim przypadku, gdy metoda jest zsynchronizowana, masz rację. Nie ma sensu sprawdzać dwa razy.

2

Jest to nieudana próba uzyskania Double Checked Locking Idiom. Pierwszym sprawdzeniem jest sprawdzenie, czy instancja została już utworzona i jeśli jest to not null, wystarczy zwrócić instancję już utworzoną.

Ale sprawdzić stan jest zameldowania wówczas akt sytuacja i jest nie wątku bezpieczne, więc istnieje możliwość, że dwa lub więcej wątków będzie widać wartość jako null i utworzyć dwie instancje Singleton i to jest doubleton lub może ManyTon.

Używamy więc synchronized, więc tylko jeden wątek wchodzi do tego bloku i tworzone jest tylko jedno wystąpienie.

+0

Doskonałe wyjaśnienie na temat podwójnie sprawdzanego identyfikatora blokowania. – Deepak

+0

Ponieważ metoda jest zsynchronizowana, prawdopodobnie nie ma potrzeby używania podwójnie sprawdzanego blokowania? –

+0

Utrzymanie metody singleton powoduje, że dzieje się to przed nawiązaniem relacji, więc można mieć tylko jedną kontrolę zerową. UWAGA: Ta metoda będzie działać źle, ponieważ blokuje klasę. Dlatego lepiej nie synchronizować metody, ale zastosować technikę, o której już wspominano w innych odpowiedziach. –

0

Technika ta nazywana jest sprawdzaniem podwójnym.

Kod wklejony jest jednak niepoprawny. Masz rację, nie ma sensu podwójnie sprawdzać wartości pustej w ten sposób. Powiedziałbym, że prawidłowa realizacja podwójnego sprawdzenia jest następujący:

private static volatile ProcessManager instance = null; 

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

Zauważ, że druga kontrola zerowa jest zsynchronizowany na obiekcie ProcessManager.class. Jest to konieczne, ponieważ metoda getInstance() jest statyczna.

+1

To wygląda na uszkodzone, chyba że instancja jest niestabilna - pierwszy odczyt instancji 'if (instance == null)' nie jest zsynchronizowany. – assylias

+0

Tak, masz rację. –

Powiązane problemy