2013-04-10 13 views
8

Czy słowo kluczowe synchronizuj musi być zastosowane do każdej metody klasy implementującej wzorzec singletowy?Synchronizacja Java w pojedynczym wzorze

public class Singleton { 

    private Singleton(){} 

    public synchronized static Singleton getInstance() 
    { 
     if(instance == null) 
      instance = new Singleton(); 

     return instance; 
    } 

    public void DoA(){ 
    } 
} 

Od Singletons nie wystawiać konstruktora publicznego i metody getInstance() jest zsynchronizowane, nie trzeba synchronizować metody DOA i wszelkie inne metody publiczne odsłonięte przez klasę Singleton.

Czy to rozumowanie jest prawidłowe?

+2

En ogóle sychronization zależy czy masz dostęp do współdzielonych danych w metodzie. – PeterMmm

+0

[To powinno odpowiedzieć na twoje pytanie] (http://stackoverflow.com/questions/777849/proper-usage-of-synchronized-singleton) – user1406177

+1

Nie sądzę, jeśli getInstance jest zsynchronizowane. to nie znaczy, że DoA jest zsynchronizowane. także. –

Odpowiedz

16

To jak każda inna klasa. Może lub nie może wymagać dalszej synchronizacji.

Rozważmy następujący przykład:

public class Singleton { 

    private Singleton() {} 

    public synchronized static Singleton getInstance() { ... } 

    private int counter = 0; 

    public void addToCounter(int val) { 
    counter += val; 
    } 
} 

Jeśli klasa ma być używany z wielu wątków, addToCounter() ma sytuacji wyścigu. Jednym ze sposobów, aby naprawić to poprzez addToCounter() zsynchronizowane:

public synchronized void addToCounter(int val) { 
    count += val; 
    } 

Istnieją inne sposoby naprawienia sytuacji wyścigu, na przykład przez zastosowanie AtomicInteger:

private final AtomicInteger counter = new AtomicInteger(0); 

    public void addToCounter(int val) { 
    counter.addAndGet(val); 
    } 

Tutaj mamy ustalony stan wyścigu bez użycia synchronized.

+0

Jak mogę rozwiązać problem z PMD "Użyj poziomu bloku zamiast synchronizacji poziomu metody" w getInstance? – rodi

+0

dzięki za wskazówkę na temat "AtomicInteger". – asgs

9

Cóż, celem klasy Singleton jest to, że istnieje co najwyżej jeden jej przypadek i że wszystkie wątki mają dostęp do tego samego obiektu.

Jeżeli nie będzie synchronizować metody getInstance dodaje się może zdarzyć

thread1 wchodzi getInstance()

thread2 wchodzi getInstance()

thread1 ocenia instance == null do true

thread2 ocenia instance == null do true

thread1 przypisuje instance i zwraca

thread2 re przypisuje instance = new Singleton() i powraca.

Teraz oba wątki mają instancję różniczkową klasy Singleton, której powinno zapobiegać ten wzorzec.

Synchronizacja zapobiega jednoczesnemu dostępowi obu wątków do tego samego bloku kodu. Tak więc synchronizacja jest potrzebna w środowisku wielowątkowym podczas tworzenia klas singletowych.

Zakładając, że wiele wątków będzie próbowało uzyskać dostęp do metod Singletonów, w tym samym czasie synchronizacja może być również konieczna w przypadku tych metod. Zwłaszcza jeśli zmieniają dane zamiast tylko je czytać, to prawda.

+0

Myślę, że pytanie dotyczy publicznych metod instancji Singleton, a nie statycznych 'getInstance'. – afsantos

+0

Tak, powinienem być bardziej cierpliwy i przeczytać odpowiedź zanim odpowiem. Rozwiążę odpowiedź ... – DeltaLima

1

Prawidłowe (Best faktycznie) sposobem korzystania Singleton

private static singleton getInstance() { 
    if (minstance == null) { 
     synchronized (singleton.class) { 
      if (minstance == null) { 
       minstance = new singleton(); 
      } 
     } 
    } 
    return minstance; 
} 
+0

, jeśli 'minstance' ma wartość null, wtedy synchronizacja bloku z tą instancją spowoduje' NullPointerException'. – asgs

+0

Tak. Właściwie napisałem poprzedni kod w pośpiechu. ;) – gaurav414u

+0

to jest zły pretekst - jest to podwójnie sprawdzany wzór blokowania - i nie będzie działać mimo wszystko - wyjaśnienie tutaj http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html –

1

leniwe inicjowanie i nici bezpieczne rozwiązanie:

public class Singleton { 

    public static class SingletonHolder { 
     public static final Singleton HOLDER_INSTANCE = new Singleton(); 
    } 

    public static Singleton getInstance() { 
     return SingletonHolder.HOLDER_INSTANCE; 
    } 
}