Singleton模式可能是應(yīng)用最廣泛的模式之一了, 但有些錯誤的應(yīng)用。
?Singleton的實(shí)現(xiàn): 有兩種方式, 如下:
1. class Test {
public static final Test instance = new Test();
private Test() {}
}
?2. class Test {
private static final Test instance = new Test();
private Test() {}
public static Test getInstance() {
return instance;
}
}
這兩種方法都要求構(gòu)造器是私有的, 這樣就可以防止該類外的對象創(chuàng)建新的TEST對象。
但相對而言, 推薦使用第二種方法, 因?yàn)槠涓哂徐`活性,當(dāng)我們改變創(chuàng)建對象的方式的時候, 不需要改動客戶代碼。 第一種方法較第二種有一點(diǎn)完全可以忽略不計的效率的提高。
?但應(yīng)避免如下代碼實(shí)現(xiàn)Singleton:
class Test {
private static Test singleton = null;
private Test() {}
public Test getSingleton() {
if(singleton == null) {
singleton = new Test();
}
return singleton;
}
}
因?yàn)閲?yán)格上講, 這并不能完全實(shí)現(xiàn)Singleton模式,而且會導(dǎo)致程序出錯, 這同著名的線程問題--DCL實(shí)效的原理是完全一樣的:
JVM創(chuàng)建對象的過程可以分為幾個步驟:創(chuàng)建空間, 把所有的變量賦值位默認(rèn)值, 初始化。。。 當(dāng)有兩個線程A和B同事進(jìn)入該方法, A先執(zhí)行, A創(chuàng)建Test實(shí)例的空間, 這時,因?yàn)镃PU的指令流機(jī)制,時間片段正好輪到B線程, 這時B判斷singleton是否為NULL, 因?yàn)锳已經(jīng)為Test的實(shí)例分配了空間, 所以JVM認(rèn)為實(shí)例已經(jīng)創(chuàng)建了, B繼續(xù)執(zhí)行, 更糟糕的是B調(diào)用了singleton, 這時因?yàn)樗]有初始化完全, 所以拋出NullPointerException, 太糟糕了!