單例模式和雙重檢查鎖定

相信大家對單例模式應該不陌生,每個人都能寫出好多種單例模式的實現(xiàn),總結來說就有五種:懶漢、餓漢、靜態(tài)內部類、枚舉和雙重檢查鎖定。針對這幾種方式的代碼,可以在網(wǎng)上搜索到,這里就不再細說。

最近又看了一遍單例的幾種實現(xiàn)方式,發(fā)現(xiàn)了一些其他東西。先看以下單例模式的實現(xiàn)代碼

public?classSingleton2?{

privateSingleton2(){}

private?staticSingleton2instance;

public?static?synchronizedSingleton2?getInstance()?{

if(instance==null)?{

instance=newSingleton2();

}

returninstance;

}

}

這種實現(xiàn)方式利用了同步的方式保證線程安全,但是效率特別低下,同步鎖要善用。

為了提高效率,可以把同步鎖放到方法里,先判斷instance是否為空,若不為空加鎖進行初始化,若為空就可以直接獲取對象,這樣可以減少一大部分的線程等待,代碼如下:

public?classSingleton7?{

privateSingleton7(){}

private?staticSingleton7instance;

public?staticSingleton7?getInstance()?{

if(instance==null)?{

synchronized(Singleton7.class)?{

if(instance==null)?{

instance=newSingleton7();

}

}

}

returninstance;

}

}

現(xiàn)在提個問題,以上代碼真的正確嗎?覺得代碼沒問題的人,可以繼續(xù)往下看,能看出問題的,估計下面的東西也知道。

這里先把問題點明,以上代碼中這一行private?staticSingleton7instance;是有問題的,缺少了修飾符volatile,這個可是很重要的。

這里先說明類初始化大概的流程:

1、分配內存空間

2、初始化對象

3、設置instance指向分配的內存地址

但是在這三步中,第二步和第三步是可以調換順序的,也即

1、分配內存空間

3、設置instance指向分配的內存地址

2、初始化對象

基于上面的理論,以上代碼在缺少volatile的情況下,會有以下問題


從圖中大致能看出B線程雖然獲取到了instance對象,但這個對象其實沒有真正初始化。

知道這個問題之后,volatitle在這里就能起到至關重要的作用了,使用了volatitle之后,在JDK1.5之后,類初始化流程中第二步和第三步在多線程的情況會被禁止,從而保證代碼的正常執(zhí)行。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容