1. 程式人生 > >設計模式之單例模式與執行緒安全問題

設計模式之單例模式與執行緒安全問題

前言

單例模式分為“餓漢模式”與“懶漢模式”。今天我們來聊聊單例模式,特別是在多執行緒中我們需要特別注意。

餓漢模式

class Singleton{
    private static Singleton singleton = new Singleton();

    private Singleton(){}

    public static Singleton getInstance(){
        return singleton;
    }
}

這種模式稱之為單例模式的餓漢模式。該模式是執行緒安全的。

懶漢模式

class LazySingleton{
    private static LazySingleton lazySingleton;

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        if(lazySingleton == null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}

這種方式為單例模式的懶漢模式,只有在第一次呼叫的時候才會去初始化物件。這種情況在多執行緒情況下會出現非執行緒安全問題。那麼我們就來解決懶漢模式的執行緒安全問題。

同步方法解決

class LazySingleton{
    private static LazySingleton lazySingleton;

    private LazySingleton(){}

    synchronized public static LazySingleton getInstance(){
        if(lazySingleton == null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}

使用synchronized關鍵字把get方法設定為同步方法,可以解決執行緒安全問題,但是效率低是一個問題,那麼我們考慮優化一下這個效率,我們可以使用同步程式碼塊,因為我們只是在初始化處會出現執行緒安全問題。

同步程式碼塊解決

class LazySingleton{
    private static LazySingleton lazySingleton;

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        synchronized(LazySingleton.class) {
            if (lazySingleton == null) {
                lazySingleton = new LazySingleton();
            }
        }
        return lazySingleton;
    }
}

同步程式碼塊也可以解決執行緒安全問題,但是上面的方式其實跟同步方法效率上沒有什麼很大不同。我們關鍵的同步程式碼其實是lazySingleton = new LazySingleton();只要給它加上同步標識就可以,但是這樣會有一個問題就是多個執行緒判斷了需要初始化該類例項,但只能有一個操作,後面的阻塞,這個時候一但前面執行緒例項化完後,後面的執行緒又會例項化,所以我們需要進行再次的檢查,判斷是否已經例項化了,這就是DCL(雙重檢查)實現更細粒度的同步程式碼塊。

DCL解決

class LazySingleton{
    private static LazySingleton lazySingleton;

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        if(lazySingleton == null) {
            synchronized (LazySingleton.class) {
                if (lazySingleton == null) {
                    lazySingleton = new LazySingleton();
                }
            }
        }
        return lazySingleton;
    }
}

那麼說到這裡就把單例模式介紹完了,上述問題中如果有什麼錯誤的地方,請留言告訴我,我會第一時間修改,以防止誤導讀者。謝謝!