2012-12-19 21 views
5


Napisałem poniżej kod w statycznej metodzie fabrycznej, aby zwrócić pojedynczą instancję DefaultCache.Fabryczna metoda tworzenia instancji singleton

public static ICache getInstance() { 
    if (cacheInstance == null) { 
     synchronized (ICache.class) { 
     if (cacheInstance == null) { 
      cacheInstance = new DefaultCache(); 
     } 
     } 
    } 
    return cacheInstance; 
} 

Czy naprawdę potrzebujemy 2nd czek null dla cacheInstance wewnątrz bloku zsynchronizowanego?

+2

Oprócz odpowiedzi, zajrzyj na c2.com/cgi/wiki?SingletonsAreEvil – Slauster

+0

Możesz przeczytać artykuł w Wikipedii na temat [Double-checked locking] (http://en.wikipedia.org/wiki/Double_checked_locking_pattern #Usage_in_Java) –

Odpowiedz

-1

Posiadać prywatnego konstruktora, aby uniknąć wszystkich tych kontroli.

class Singleton { 
    private static final Singleton instance = new Singleton(); 

    private Singleton() { 
    } 

    public static final Singleton getInstance() { 
     return instance; 
    } 
} 
0

Zakładając cacheInstance jest statyczny należy rozważyć dwie możliwe strategie inicjalizacji:

  • Lazy initilization: Pole Singleton jest wypełniana instancji w momencie, kiedy to po raz pierwszy użyty (jak na swoje przykład).

  • Inicjalizacja (Standarad): Pole singleton jest wypełnione instancją zaraz po załadowaniu klasy przez maszynę JVM.

Więc jeśli zamierzasz używać leniwej inicjalizacji, powinieneś sprawdzić, czy nie ma to wartości zerowej, w przeciwnym razie po prostu zwrócisz wskaźnik zerowy.

Alternatywnie można również zainicjować pole w bloku statycznym.

//class declaration 
static { 
    cacheInstance = new DefaultCache(); 
} 

lub w tym samym wierszu, w którym deklarują, że

private static final DefaultCache cacheInstance = new DefaultCache(); 
4

chciałbym uniknąć konieczności sprawdzania rywalizacją używając leniwie zainicjowany pojedyncza:

public class Singleton { 
    public static ICache getInstance() { 
     return LazyCacheInitializer.INSTANCE; 
    } 

    private class LazyCacheInitializer { 
     private static final ICache INSTANCE = new DefaultCache(); 
    } 
} 
+0

Jaka jest przewaga tego nad używaniem 'wyliczenia'? –

+0

to jest poprawne. – JIV

+1

@Peter Cóż, wadą wyliczeń jest ich model serializacji. Enums serializuje tylko ich nazwy, ale nie ich stan. Jeśli singleton może mieć dowolny stan, zostanie utracony. Jako takie, wyliczenia ze stanem nie mogą być wysyłane przez sieć lub zapisane i odzyskane z dysku. Nie jestem pewien, czy warto byłoby pomyśleć o serializowaniu pamięci podręcznej singletonu w tym konkretnym przypadku, ale twoje pytanie dotyczyło zalet/wad. –

6

Musisz drugi czek ponieważ wartość mogła zostać ustawiona przez inny wątek podczas próby uzyskania blokady. W rzeczywistości nie masz bezpiecznego widoku tej wartości, dopóki nie znajdziesz się w zsynchronizowanym bloku. Mogło to zostać ustawione przez inny wątek jakiś czas temu.

Najprostszym leniwy Singleton jest użycie enum

public enum DefaultCache implements ICache { 
    INSTANCE 
} 

Zakładam, że nie robią tego tak można zmienić realizacji.

BTW: Sugeruję, aby w miarę możliwości używać tylko bezstanowych singletonów i używać iniekcji dependanecy dla wszystkich obiektów stanowych tak bardzo, jak to możliwe.

+0

+1 dla wyliczanki (byłeś szybszy ode mnie) :) –

1

Tak, w przeciwnym razie można utworzyć więcej niż dwie instancje. Załóżmy, że masz więcej niż jeden wątek. Pierwszy test jest wykonywany w warunkach ras, tzn. Niektóre wątki widzą zmienną równą zeru i próbują ustawić instancję. Bez drugiej kontroli każdy wątek utworzy nową instancję.

0

zawsze można użyć w oparciu wdrożenie Singleton z enum jak Peter pisał, ale należy pamiętać, że wszystkie implementacje są samotnymi w klasie ładowarka.

Należy również zwrócić uwagę na interfejs Cloneable.

Powiązane problemy