面試官讓你手寫單例模式

第一次聽說讓寫設計模式,我都懵了,但是還真有讓手寫的呢,今天來手寫一波單例模式。
單例模式,也就是一個實例唄,當我們獲得對象的時候,每次獲得的都是同一個,那麼我們可以先創建好一個實例,然後寫一個get方法,每次創建的時候,通過get方法獲取該實例,那麼就達到了單例效果,需要注意的是,我們要私有構造方法,以免外面new對象。

public class Singleton {
    public static Singleton instance = new Singleton();

    private Singleton(){
        
    }

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

這種寫法,習慣上稱之爲餓漢式,原因很簡單,因爲在獲取對象之前都創建好了,感覺“很餓”,這樣其實不好,因爲我都沒有用到這個對象,你都創建了,多浪費呀,說的也是,於是我們改爲,當用到的時候,我們判斷instance是否爲null,如果爲null,我們就創建,否則就直接return。

public class Singleton {
    public static Singleton instance;

    private Singleton(){

    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

這種方式是等用到了纔去創建,給人的感覺是很懶,所以又叫“懶漢式”,仔細看看這種寫法,其實存在線程安全問題,當有多線程調用getInstance方法的時候,第一個線程判斷instance爲null,進入了 if,當還沒來得及創建對象的時候,第二個線程也判斷instance爲null,也進入了 if,於是就會創建多個對象,無法達到單例效果,所以我們就引入了鎖,也就是synchronized

public class Singleton {
    public static Singleton instance;

    private Singleton(){}

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

這樣有效的解決了線程安全的問題,但是,這個鎖,鎖到了方法上,範圍有點大了,其實我們只需要鎖出現線程安全的一部分就行了,於是又來了新版本

public class Singleton {
    public static Singleton instance;

    private Singleton(){}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }

        return instance;
    }
}

這樣一來,只鎖了new對象的那一部分,當線程來了的時候,我先判斷instance是否爲空,爲空就上鎖,不空直接return,但是問題來了,當出現多線程時,第一個線程判斷instance爲null,進入鎖,還沒來得及創建對象,第二個線程來了判斷instance也爲null,當第一個線程走了之後,第二個線程也進入了鎖,執行了new,這樣線程也不安全了,於是出現了終極版!,也叫做DCL(Double Check Lock)

public class Singleton {
    public static Singleton instance;

    private Singleton(){}

    public static Singleton getInstance() {
        if (instance == null) { Check one
            synchronized (Singleton.class) {
                if (instance == null) { Check two
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

這樣一來,多線程的情況下,當多個線程進入了第一個 if,但是當第一個 if 執行完畢後,其他線程就算進入鎖,也無法通過第二個 if 判斷。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章