標籤:通過 線程鎖 相關 initial 成員 初始化 成員變數 hello rgs
/*多線程下的單例*///餓漢式class Single{ private static final Single s = new Single(); private Single(){} public static Single getInstance() { return s; }}
/*懶漢式加入同步為瞭解決多安全執行緒問題。加入雙重判斷是為瞭解決效率問題。*/class Single{ private static Single s = null; private Single(){} public static Single getInstance() { if(s==null) { synchronized(Single.class) { if(s==null) // -->0 -->1 s = new Single(); } } return s; }}class SingleDemo{ public static void main(String[] args) { System.out.println("Hello World!"); }}一種更好的單例實現方法
餓漢式單例類不能實現消極式載入,不管將來用不用始終佔據記憶體;懶漢式單例類安全執行緒控制煩瑣,而且效能受影響。可見,無論是餓漢式單例還是懶漢式單例都存在這樣那樣的問題,有沒有一種方法,能夠將兩種單例的缺點都克服,而將兩者的優點合二為一呢?答案是: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); } }
編譯並運行上述代碼,運行結果為:true,即建立的單例對象s1和s2為同一對象。由於靜態單例對象沒有作為Singleton的成員變數直接執行個體化,因此類載入時不會執行個體化Singleton,第一次調用getInstance()時將載入內部類HolderClass,在該內部類中定義了一個static類型的變數instance,此時會首先初始化這個成員變數,由Java虛擬機器來保證其執行緒安全性,確保該成員變數只能初始化一次。由於getInstance()方法沒有任何線程鎖定,因此其效能不會造成任何影響。
通過使用IoDH,我們既可以實現消極式載入,又可以保證安全執行緒,不影響系統效能,不失為一種最好的Java語言單例模式實現方式(其缺點是與程式設計語言本身的特性相關,很多物件導向語言不支援IoDH)。
Java多線程下單例