單例模式作為一種常見的設(shè)計(jì)模式森书,在程序中非常常見,主要是為了保證一個類只有一個唯一的對象谎势。
從簡單的“餓漢式”凛膏、“懶漢式”→利用 synchronized 和 復(fù)雜的“雙重校驗(yàn)DCL模式”,是一個考慮線程安全的過程(其實(shí)靜態(tài)的餓漢式單例模式也是線程安全的脏榆,后文有提到)猖毫。
后來有一篇文章上說“雙重校驗(yàn)DCL模式”其實(shí)并不是線程安全的,我沒看懂他說的原因(原文在此)须喂,但后來發(fā)現(xiàn)了另一種實(shí)現(xiàn)線程安全的單例模式吁断,靜態(tài)內(nèi)部類方式,代碼如下:
public class SingletonPattern {
private SingletonPattern() {
}
private static class SingletonPatternHolder {
private static final SingletonPattern singletonPattern = new SingletonPattern();
}
public static SingletonPattern getInstance() {
return SingletonPatternHolder.singletonPattern;
}
}
剛開始我覺得這種方式挺有意思的坞生,但是不明白為什么要這么寫仔役,為此我專門請教了一位Java大神,他今天有空給我解釋了原因是己,我總結(jié)一下又兵。
在這個例子中內(nèi)部類 SingletonPatterHolder 的靜態(tài)變量 singletonPattern,這個變量是我們需要的那個單例赃泡,即外部類 SingletonPattern 的對象寒波,就是那個我們需要的唯一的對象。
當(dāng)我們調(diào)用 SingletonPattern.getInstance() 時升熊,內(nèi)部類 SingletonPatternHolder 才會初始化俄烁,靜態(tài)變量 singletonPattern 被創(chuàng)建出來。
這個實(shí)現(xiàn)思路中最主要的一點(diǎn)就是利用類中靜態(tài)變量的唯一性级野。
這種方式的優(yōu)點(diǎn)是:
- 不用 synchronized 页屠,節(jié)省時間(雖然synchronized 浪費(fèi)那個時間根本不算什么時間粹胯。唉!時間就是生命辰企,聽說不用synchronized 會快100倍风纠,哈哈!)牢贸;
- 調(diào)用 getInstance() 的時候才會創(chuàng)建對象竹观,不調(diào)用不創(chuàng)建,節(jié)省空間潜索,這有點(diǎn)像傳說中的懶漢式臭增。
剛開始我還有點(diǎn)疑惑,內(nèi)部類 SingletonPatternHolder 是靜態(tài)的竹习,那么外部類 SingletonPattern 加載的時候誊抛,內(nèi)部類 SingletonPatternHolder 會被加載,后來想起來整陌,靜態(tài)內(nèi)部類與外部類沒有什么大的關(guān)系拗窃,外部類加載的時候,內(nèi)部類不會被加載泌辫,靜態(tài)內(nèi)部類只是調(diào)用的時候用了外部類的名字而已随夸。
最后想了想,還是把靜態(tài)餓漢式單例模式也寫出來(線程安全)震放,做個比較逃魄。
public class SingletonPattern {
private static final SingletonPattern singletonPattern = new SingletonPattern();
private SingletonPattern() {
}
public static SingletonPattern getInstance() {
return singletonPattern;
}
}
這個寫法也是利用類的靜態(tài)變量的唯一性,跟上面的靜態(tài)內(nèi)部類有異曲同工之妙澜搅,不過這種方式有一點(diǎn)不足,就是類加載的時候單例對象也會跟著加載邪锌,拖延類加載速度勉躺,有時候沒用到這個類的單例對象的話,會浪費(fèi)空間觅丰。有點(diǎn)較真哈饵溅。
《本文完》