2011-11-30 57 views
1

我已經實現了Singleton類如下:Singleton模式在多線程環境中是否存在問題?

public class Singleton { 

    private static Singleton instance = null; 


    private Singleton() { 
    } 

private synchronized static void createInstance() { 
    instance = new Singletone(); 
} 


    public static Singleton getInstance() { 
     if(instance == null){ 
      createInstance(); 
     } 
     return instance; 
    } 

} 

但我想知道這是否是一個正確的實現單例。 多線程環境中是否有任何問題。

+0

錯字:它是_Singleton_而不是單數。是的,這不是一個線程安全的Singleton。 – zengr

+1

可能重複的[java單例線程安全](http://stackoverflow.com/questions/4965534/java-singleton-thread-safe) – zengr

+1

可能的重複:http://stackoverflow.com/questions/70689/efficient-way -to-implement -singleton-pattern-in-java –

回答

5

您的實施幾乎是正確的。問題是它不是線程安全的。 2個獨立的線程可以同時輸入getInstance(),檢查該實例是否爲空,然後創建2個類的實例。這裏是修復:

public static synchronized Singletone getInstance() { 
    if(instance == null){ 
     createInstance(); 
    } 
    return instance; 
} 

請注意字​​。

0

這是singleton模式的正確實現,雖然你並不真的需要一個createInstance方法;你可以在getInstance中直接插入。另外,它拼寫爲「Singleton」,最後沒有「e」。

假設你可以在多線程環境中創建一個問題。如果兩個幀指針同時進入getInstance,那麼先輸入的那個可以得到一個實例Singleton,而第二個會得到另一個實例。

這取決於你如何使用它。如果您在設置線程之前使用單例,則不會有任何問題。如果這是一個問題,你可以考慮首先初始化單例。您也可以通過在方法聲明中使用​​關鍵字來解決此問題。

7
public enum Singleton { 
    INSTANCE; 
    private int val; 

    public int getVal() { 
     return val; 
    } 
} 

用法:

Singleton.INSTANCE.getVal(); 

這是,你必須支持ENUM的Java版本> 5.0的完美單。

也在Joshua Bloch的Effective Java中提到。一篇博客文章在這裏:Enum Singleton

更新:
另外,請用單身,只有當你是100%肯定,你需要一個!它殺死了代碼的可測試性!但是你不能避免在某些地方避免它,比如在工廠裏。
但請不要濫用它,在任何你真正需要的地方使用它。瞭解它的用途。

+0

@Downvoter:小心解釋一下嗎? – zengr

+1

對不起,偶然downvoted,事實證明,我不能清除,所以這+1是下一個最好的事情。 –

-1

你的實現似乎很好。單個JVM中的多線程對於那種單例問題不是問題,但它會在集羣(兩個或多個JVM)中導致問題。

請參閱http://java.sun.com/developer/technicalArticles/Programming/singletons/瞭解這些問題。

哦,這是單身人士,而不是單身人士。 :)

+2

實際上,即使在單個JVM中,它也是** ** **可能***多線程問題。您的鏈接也涵蓋了「由於錯誤同步導致的多個實例」。 – Boris

0

單身不是線程安全的。正是這個原因,Double-checked Locking被引入。

從Java SE 5及更高版本開始,您可以使用volatile您的靜態實例。 Java VM將知道如何在多線程運行時正確處理單例。

更多關於Double-checked locking

+0

從包含的鏈接中可以看出:「這種技術存在許多微妙的問題,通常應該避免」 –

0

對於惰性初始化實現(您的情況),應該同步getInstance()方法以確保線程安全。

public static synchronized Singleton getInstance() 

或者您可以簡單地在類加載時已經線程安全地初始化它。

private static Singleton instance = new MySingleton(); 
2

除了上面的枚舉之外,我遇到過的最好的機制稱爲靜態初始化。有了這個,你就可以依靠Java的內存模型的保證,所以它可以始終工作。下面是從an answer to a different question一個片段演示了這一點:

class Singleton { 
    static class SingletonHolder { 
     static final Singleton INSTANCE = new Singleton(); 
    } 
    public static Singleton instance() { 
     return SingletonHolder.INSTANCE; 
    } 
} 

Singleton實例的SingletonHolder類對象將要創建的第一次SingletonHolder.INSTANCE被調用。

Java內存模型保證靜態代碼(new Singleton())只能由一個線程執行。所以沒有雙重檢查鎖定(這不起作用),並沒有不必要的同步。所有後續的調用都將獲取該實例。