1.關(guān)于雙檢測(cè)鎖定DCL的問(wèn)題
public class SingletonKerriganD {
/**
* 單例對(duì)象實(shí)例
*/
private static SingletonKerriganD instance = null;
public static SingletonKerriganD getInstance() {
if (instance == null) {
synchronized (SingletonKerriganD.class) {
if (instance == null) {
instance = new SingletonKerriganD(); //A
}
}
}
return instance;
}
}
A處的代碼的匯編大致執(zhí)行如下幾步
1.分配內(nèi)存
2.初始化
3.變量指向這個(gè)內(nèi)存
在java上由于支持處理器亂序執(zhí)行,2和3的順序是不定的,假如3先執(zhí)行了,那么第二個(gè)線程在訪問(wèn)的時(shí)候會(huì)因?yàn)樽兞坎粸榭罩苯臃祷?,但這時(shí)還沒(méi)有初始化,所以可以遇見的一定會(huì)報(bào)錯(cuò)。
在c語(yǔ)言中是可行的,在java1.5以后呢引入了volatile ,volatile修飾的變量,保證每次都從堆中讀取,保證在2,3沒(méi)有完全執(zhí)行完的時(shí)候不會(huì)有人可以訪問(wèn)到他。會(huì)影響一定的效率
那么可以采用內(nèi)部靜態(tài)類的方式。
public class SingletonKerrigan implements Serializable {
private static class SingletonHolder {
/**
* 單例對(duì)象實(shí)例
*/
static final SingletonKerrigan INSTANCE = new SingletonKerrigan();
}
public static SingletonKerrigan getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* private的構(gòu)造函數(shù)用于避免外界直接使用new來(lái)實(shí)例化對(duì)象
*/
private SingletonKerrigan() {
}
/**
* readResolve方法應(yīng)對(duì)單例對(duì)象被序列化時(shí)候
*/
private Object readResolve() {
return getInstance();
}
}