相信大家對(duì)單例模式應(yīng)該不陌生贾陷,每個(gè)人都能寫出好多種單例模式的實(shí)現(xiàn),總結(jié)來說就有五種:懶漢嘱根、餓漢髓废、靜態(tài)內(nèi)部類、枚舉和雙重檢查鎖定该抒。針對(duì)這幾種方式的代碼慌洪,可以在網(wǎng)上搜索到,這里就不再細(xì)說柔逼。
最近又看了一遍單例的幾種實(shí)現(xiàn)方式蒋譬,發(fā)現(xiàn)了一些其他東西。先看以下單例模式的實(shí)現(xiàn)代碼
public?classSingleton2?{
privateSingleton2(){}
private?staticSingleton2instance;
public?static?synchronizedSingleton2?getInstance()?{
if(instance==null)?{
instance=newSingleton2();
}
returninstance;
}
}
這種實(shí)現(xiàn)方式利用了同步的方式保證線程安全愉适,但是效率特別低下犯助,同步鎖要善用。
為了提高效率维咸,可以把同步鎖放到方法里剂买,先判斷instance是否為空,若不為空加鎖進(jìn)行初始化癌蓖,若為空就可以直接獲取對(duì)象瞬哼,這樣可以減少一大部分的線程等待,代碼如下:
public?classSingleton7?{
privateSingleton7(){}
private?staticSingleton7instance;
public?staticSingleton7?getInstance()?{
if(instance==null)?{
synchronized(Singleton7.class)?{
if(instance==null)?{
instance=newSingleton7();
}
}
}
returninstance;
}
}
現(xiàn)在提個(gè)問題租副,以上代碼真的正確嗎坐慰?覺得代碼沒問題的人,可以繼續(xù)往下看用僧,能看出問題的结胀,估計(jì)下面的東西也知道。
這里先把問題點(diǎn)明责循,以上代碼中這一行private?staticSingleton7instance;是有問題的糟港,缺少了修飾符volatile,這個(gè)可是很重要的院仿。
這里先說明類初始化大概的流程:
1秸抚、分配內(nèi)存空間
2、初始化對(duì)象
3歹垫、設(shè)置instance指向分配的內(nèi)存地址
但是在這三步中剥汤,第二步和第三步是可以調(diào)換順序的,也即
1排惨、分配內(nèi)存空間
3吭敢、設(shè)置instance指向分配的內(nèi)存地址
2、初始化對(duì)象
基于上面的理論若贮,以上代碼在缺少volatile的情況下省有,會(huì)有以下問題
從圖中大致能看出B線程雖然獲取到了instance對(duì)象,但這個(gè)對(duì)象其實(shí)沒有真正初始化谴麦。
知道這個(gè)問題之后蠢沿,volatitle在這里就能起到至關(guān)重要的作用了,使用了volatitle之后匾效,在JDK1.5之后舷蟀,類初始化流程中第二步和第三步在多線程的情況會(huì)被禁止,從而保證代碼的正常執(zhí)行面哼。