1. 程式人生 > >Java多線程下單例

Java多線程下單例

不能 pla init 能夠 餓漢 技術 安全性 ron 解決

/*
多線程下的單例

*/

//餓漢式
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多線程下單例