設計模式之單例模式與線程安全問題

前言

單例模式分爲「餓漢模式」與「懶漢模式」。今天咱們來聊聊單例模式,特別是在多線程中咱們須要特別注意。安全

餓漢模式

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;
    }
}

這種方式爲單例模式的懶漢模式,只有在第一次調用的時候纔會去初始化對象。這種狀況在多線程狀況下會出現非線程安全問題。那麼咱們就來解決懶漢模式的線程安全問題。ide

同步方法解決

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;
    }
}

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

相關文章
相關標籤/搜索