DCL 單例是否需要volatile 關鍵字修飾

單例(Singleton)

簡答的說就是整個jvm 中只有一個對象

單例分爲懶漢模式和餓漢模式

餓漢: 就是聲明對象的收直接new

public class Singleton {

    private static Singleton singleton = new Singleton ();

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

懶漢: 在使用的時候創建對象

public class Singleton {

    private static Singleton singleton;

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

以上的方式僅僅針對單線程,在併發情況下, 還是會存在多個singleton 對象.

synchronzied 直接加載方法上(不推薦,鎖太重),可以保證併發情況下的只有一個對象.

優化一下: (懶漢模式)

public class Singleton {

    private static Singleton singleton;

    private Singleton () {}
    
    public static Singleton getInstance () {
        if (singleton == null) {
            synchonized (Singleton.class) {
                singleton = new Singleton ();
            }
        }
        return singleton;
    }
}

但 這個還不是併發安全的方式

比如

thread 1 到 synchronized 處, thread 2 也到這裏,但是thread 2 繼續執行, 調用了構造器最後返回, thread 1 繼續執行, 又會執行一次構造器,然後返回,這就導致不是隻有一個對象.

再次優化 就出現 DCL(Double Check Lock) 單例, 在獲取鎖之後,再次檢驗對象是否爲 null

public class Singleton {

    private static volatile Singleton singleton;

    private Singleton () {}
    
    public static Singleton getInstance () {
        if (singleton == null) {
            synchonized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton ();
                }        
            }
        }
        return singleton;
    }
}

這裏面使用了volatile, 因爲在對象初始化過程中,沒有 volatile ,會發生指令重排序的情況,導致使用半初始化的對象,有了volatile,會禁止指令重排序,所有的指令都是按照順序執行.

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