JAVA單例模式 – JAVA編程語言程序開發技術文章

java單例大傢都熟悉,下面總結幾個簡單例子
首先是經典單例模式:
[java]
/*
 * 經典單例模式
 */ 
public class SimpleInstance1 { 
    private static SimpleInstance1 instance = null; 
    private SimpleInstance1(){}; 
    public static SimpleInstance1 getInstance(){ 
        if (instance == null){ 
            return new SimpleInstance1(); 
        } 
        else return instance; 
    } 

這種單例模式是在第一次調用getInstance的時候,對類進行初始化,以後調用時直接返回第一次初始化的實例。
但是這種模式不保證線程安全。例如,線程A和線程B同時第一次運行到如下語句
[java] 
if (instance == null){ 
此時2個線程的判斷都為true,所以就都進行瞭一次實例化new SimpleInstance1()。
為瞭避免這種線程不安全問題,可以使用餓漢式,如下:
[java]
/*
 * 餓漢一步到位方式
 */ 
public class SimpleInstance2 { 
    private static final SimpleInstance2 instance = new SimpleInstance2(); 
    private SimpleInstance2(){}; 
    public static SimpleInstance2 getInstance(){ 
        return instance; 
    } 

上面把初始化放到瞭static中,這樣在類裝載的時候就進行瞭初始化,確實可以保證線程安全(因為真正開始調用getInstance()之前就已經初始化瞭),但是卻丟失瞭部分系統資源。而且有一個明顯的缺點,就是new SimpleInstance2()中,不能根據程序運行情況動態的往構造方法中傳入參數。
現在我們回到最初的經典單例模式,為保證線程安全,我們做如下改進:
[java] 
public class SimpleInstance3 { 
    private static SimpleInstance3 instance = null; 
    private SimpleInstance3(){}; 
    public static synchronized SimpleInstance3 getInstance(){ 
        if (instance == null){ 
            return new SimpleInstance3(); 
        } 
        else return instance; 
    } 

我們在getInstance方法中加入synchronized關鍵字,保證同一時刻隻有一個線程可以進入此方法。這樣確實可以保證線程安全,而且也是在真正需要用到此類的時候進行第一次初始化的,但是這樣進行線程同步,性能開銷很客觀。
其實做出線程同步的目的,是防止首次初始化的時候出現線程不安全的情況,而上面的模式中,不僅首次初始化時要線程同步,即使初始化之後調用getInstance也進行線程同步限制瞭,不僅沒必要,還浪費瞭時間。針對這種情況進行如下的改進:
[java] 
/*
 * 雙重鎖定模式
 */ 
public class SimpleInstance4 { 
    private volatile static SimpleInstance4 instance = null; 
    private SimpleInstance4(){}; 
    public static SimpleInstance4 getInstance(){ 
        if (instance == null){ 
            synchronized (SimpleInstance4.class) { 
                if (instance == null){ 
                    return new SimpleInstance4(); 
                } 
            } 
        } 
        return instance;  www.aiwalls.com
    } 

這個不多解釋瞭,隻在初始化的那部分代碼中加入線程同步,相比上面的那種同步小有改進。不過instance也被定義為volatile,因為new操作在jdk1.5以前不是一個規范安全的過程(具體可以參看jvm方面的資料),這樣也消耗瞭不少系統時間。

 

作者:laizhenhai88

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。