2013-04-10 65 views
8

是否需要將synchronized關鍵字應用於實現此類單例模式的類的每個方法?Java以單例模式同步

public class Singleton { 

    private Singleton(){} 

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

     return instance; 
    } 

    public void DoA(){ 
    } 
} 

由於單身不公開公共構造函數和getInstance()方法是同步的,一個不需要同步方法的DoA和由Singleton類暴露任何其他公共方法。

這個推理是否正確?

+2

恩一般sychronization依賴。 – PeterMmm 2013-04-10 15:53:37

+0

[這應該回答你的問題](http://stackoverflow.com/questions/777849/proper-usage-of-synchronized-singleton) – user1406177 2013-04-10 15:55:04

+1

我不這麼認爲,如果getInstance是同步。這並不意味着DoA是同步的。太。 – 2013-04-10 15:55:38

回答

16

它就像任何其他類一樣。它可能需要也可能不需要進一步的同步。

考慮下面的例子:

public class Singleton { 

    private Singleton() {} 

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

    private int counter = 0; 

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

如果類是從多個線程所使用的,addToCounter()具有競爭狀態。要解決這個問題的方法之一是通過使addToCounter()同步:

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

還有其他的方法來解決競爭條件,例如,通過使用AtomicInteger

private final AtomicInteger counter = new AtomicInteger(0); 

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

在這裏,我們已經解決了競爭條件而不使用​​。

+0

如何在getInstance上解決PMD錯誤「使用塊級別而非方法級別同步」? – rodi 2015-02-10 17:17:41

+0

感謝您對AtomicInteger的建議。 – asgs 2015-03-28 18:49:46

9

那麼,Singleton類的目的是最多隻有一個實例,所有線程都可以訪問同一個對象。

如果你不同步getInstance方法如下可能發生

線程1進入getInstance()

線程2進入getInstance()

線程1計算instance == nulltrue

線程2計算instance == nulltrue

線程1分配instance並返回

線程2 重新分配instance = new Singleton()並返回。

現在線程都有一個Singleton類的不同實例,這是本模式應該阻止的。

同步會阻止兩個線程同時訪問同一個代碼塊。因此,當您實例化單例類時,需要在多線程環境中進行同步。

現在假設多個線程將嘗試訪問Singletons方法,同時這些方法也可能需要同步。特別是如果他們改變數據而不是隻讀數據,這是真的。

+0

我認爲這個問題引用了Singleton實例的公共方法,而不是靜態的'getInstance'。 – afsantos 2013-04-10 16:06:01

+0

是的,我應該更耐心,在回答之前閱讀這個問題。我將擴展答案... – DeltaLima 2013-04-10 16:07:50

1

正確的(最佳實際)的方式來使用辛格爾頓

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

如果'minstance'恰好爲空,那麼將該塊與該實例同步將導致'NullPointerException'。 – asgs 2015-03-28 18:51:45

+0

是的。其實我匆匆寫了以前的代碼。 ;) – gaurav414u 2015-07-20 06:22:52

+0

這是一個不好的實踐 - 它是雙重檢查鎖定模式 - 並且畢竟不會工作 - 在這裏解釋http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html – 2016-08-30 07:50:06

1

延遲初始化和線程安全的解決方案:如果您在方法訪問共享數據

public class Singleton { 

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

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