線程安全的單例模式

最常見的懶漢模式下的核心代碼

if(instance == null) {
instance = new Singleton();
}

如果一個線程在第二行的賦值語句發生之前切換,那麼成員變量instance仍然是null,然後另一個線程可能接下來進入到if塊中。在這種情況下,兩個不同的單例類實例就被創建。

尋找一種性能改進方法時,你可能會選擇像下面這樣重寫getInstance()方法:

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

這個代碼片段只同步了關鍵的代碼,而不是同步整個方法。然而這段代碼卻不是線程安全的。考慮一下下面的假定:線程1進入同步塊,並且在它給singleton成員變量賦值之前線程1被切換。接着另一個線程進入if塊。第二個線程將等待直到第一個線程完成,並且仍然會得到兩個不同的單例類實例。

雙重加鎖檢查--》終極解決方案?

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

如果兩個線程同時訪問getInstance()方法會發生什麼?想像一下線程1進行同步塊馬上又被切換。接着,第二個線程進入if 塊。當線程1退出同步塊時,線程2會重新檢查看是否singleton實例仍然爲null。因爲線程1設置了singleton成員變量,所以線程2的第二次檢查會失敗,第二個單例類實例也就不會被創建。似乎就是如此。
不幸的是,雙重加鎖檢查不會保證正常工作,因爲編譯器會在Singleton的構造方法被調用之前隨意給singleton賦一個值。如果在singleton引用被賦值之後而被初始化之前線程1被切換,線程2就會被返回一個對未初始化的單例類實例的引用。

May be the final:

public class Singleton {
public final static Singleton INSTANCE = new Singleton();
private Singleton() {
// Exists only to defeat instantiation.
}
}

這段代碼是線程安全的是因爲靜態成員變量一定會在類被第一次訪問時被創建。你得到了一個自動使用了懶漢式實例化的線程安全的實現。

原文鏈接:http://www.iteye.com/topic/60179#
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章