設計模式之單例模式

單例模式就是有且僅有一個實例化對象。這有什麼用處呢?其實有一些對象我們只需要一個,比如說:線程池、緩存、對話框、處理偏好設置和註冊表的對象、日誌對象、充當打印機顯卡等設備的驅動程序的對象。事實上,這些對象只能有一個實例,如果製造出了多個實例,就會導致許多問題產生,例如:程序的行爲異常、資源使用過量、或者是不一致的結果。

實現單例的方法:
1、首先將該類的構造方法私有化
2、然後提供一個static方法,供其他類獲得該類的實例化對象
3、在該類中初始化自己類的實例對象,或者在static方法中初始化
4、在其他類中調用該static方法即可以得到該類的實例

首先,我們先看一個單例模式的實現:

package com.xwj.singleton;

public class Singleton {
    private static Singleton uniqueInstance;
    //私有構造方法
    private Singleton(){

    }
    //獲取單例實例
    public static Singleton getInstance(){
        if(uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}

在上面的代碼中,我們可以看到Singleton類中構造方法被私有化了,因此其他類根本不能通過new Singleton()方法創建Singleton的實例。只能通過 Singleton.getInstance()獲得Singleton的實例。而且從getInstance()方法中的代碼可以看出,每次當調用getInstance()只會返回同一個實例對象uniqueInstance,由此這樣就可以自始至終只有一個Singleton對象了。

現在我們對單例模式下定義:
單例模式:確保一個類只有一個實例,並提供一個全局訪問點。

我們已經初步認識了單例模式,但是單例模式還不是我們想象中的這麼簡單,在它裏面還會有一些問題產生。例如:現在有多個線程在併發訪問singleton.getInstance()方法,比如說線程1、線程2有可能同時進入到if(uniqueInstance == null)這個判斷條件體裏面,這樣線程1通過new Singleton()創建了一個Singleton對象返回了,然後線程2也通過new Singleton()創建了一個Singleton對象返回了。這樣就不是自始至終只有一個Singleton對象實例了。
處理多線程的問題,只要把getInstance()變成同步方法,多線程災難幾乎就可以輕易的解決了,例如:

package com.xwj.singleton;

public class Singleton {
    private static Singleton uniqueInstance;
    //私有構造方法
    private Singleton(){

    }
    //獲取單例實例
    public static synchronized Singleton getInstance(){
        if(uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}

但是我們想只有第一次實例化Singleton對象時,才真正需要同步。換句話說,一旦設置好了uniqueInstance變量,就不需要同步這個方法了。之後每次調用這個方法同步都是一種累贅。
我們使用“雙重檢查加鎖”可以優化上面的代碼,同時也可以解決該多線程問題。如下:

package com.xwj.singleton;

public class Singleton {
    private volatile static Singleton uniqueInstance;
    //私有構造方法
    private Singleton(){

    }
    //獲取單例實例
    public static Singleton getInstance(){
        if(uniqueInstance == null){
            synchronized (Singleton.class) {        //同步代碼塊
                if(uniqueInstance == null){
                    uniqueInstance = new Singleton();                   
                }
            }
        }
        return uniqueInstance;
    }
}

另外我們還有一種方法解決多線程併發導致創建多個Singleton對象的問題,不使用延遲實例化的做法,如下:

package com.xwj.singleton;

public class Singleton {
    private static Singleton uniqueInstance = new Singleton();
    //私有構造方法
    private Singleton(){

    }
    //獲取單例實例
    public static Singleton getInstance(){
        return uniqueInstance;
    }
}

但是,還有一個問題存在是,我們使用這種方法,如果創建Singleton對象時非常消耗資源,而程序在這次的執行過程中又一直沒有用到它,不就形成浪費了嗎?如果存在這種情況,我們最好使用“雙重檢查加鎖”來解決多線程問題。

到此爲止,單例模式我就說這麼多了,現在對我們所學總結一下:
1、單例模式確保程序中的一個類最多隻有一個實例
2、單例模式也提供訪問這個實例的全局點
3、在java中實現單例模式需要私有的構造器、一個靜態方法和一個靜態變量
4、確定在性能和資源上的限制,然後小心的選擇適當的方法來實現單例,已解決多線程問題

發佈了86 篇原創文章 · 獲贊 42 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章