3.5 一種更好的單例實現方法
餓漢式單例類不能實現延遲加載,不管將來用不用始終佔據內存;懶漢式單例類線程安全控制煩瑣,而且性能受影響。可見,無論是餓漢式單例還是懶漢式單例都存在這樣那樣的問題,有沒有一種方法,能夠將兩種單例的缺點都克服,而將兩者的優點合二爲一呢?答案是:Yes!下面我們來學習這種更好的被稱之爲Initialization Demand Holder (IoDH)的技術。
在IoDH中,我們在單例類中增加一個靜態(static)內部類,在該內部類中創建單例對象,再將該單例對象通過getInstance()方法返回給外部使用,實現代碼如下所示:
- //Initialization on Demand Holder
- class Singleton {
- private Singleton() {
- }
- private static class HolderClass {
- private final static Singleton instance = new Singleton();
- }
- public static Singleton getInstance() {
- return HolderClass.instance;
- }
- public static void main(String args[]) {
- Singleton s1, s2;
- s1 = Singleton.getInstance();
- s2 = Singleton.getInstance();
- System.out.println(s1==s2);
- }
- }
//Initialization on Demand Holder
class Singleton {
private Singleton() {
}
private static class HolderClass {
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return HolderClass.instance;
}
public static void main(String args[]) {
Singleton s1, s2;
s1 = Singleton.getInstance();
s2 = Singleton.getInstance();
System.out.println(s1==s2);
}
}
編譯並運行上述代碼,運行結果爲:true,即創建的單例對象s1和s2爲同一對象。由於靜態單例對象沒有作爲Singleton的成員變量直接實例化,因此類加載時不會實例化Singleton,第一次調用getInstance()時將加載內部類HolderClass,在該內部類中定義了一個static類型的變量instance,此時會首先初始化這個成員變量,由Java虛擬機來保證其線程安全性,確保該成員變量只能初始化一次。由於getInstance()方法沒有任何線程鎖定,因此其性能不會造成任何影響。
通過使用IoDH,我們既可以實現延遲加載,又可以保證線程安全,不影響系統性能,不失爲一種最好的Java語言單例模式實現方式(其缺點是與編程語言本身的特性相關,很多面向對象語言不支持IoDH)。
|
至此,三種單例類的實現方式我們均已學習完畢,它們分別是餓漢式單例、懶漢式單例以及IoDH。
【作者:劉偉 http://blog.csdn.net/lovelion】