Java單例模式雙重檢查鎖定

首先要說的是,個人推薦使用餓漢模式和靜態內部類方式實現單例模式。其實,靜態內部類裏也是一個餓漢模式。
懶漢模式中,雙重檢查鎖定代碼如下:

public class Singleton{   
    // 靜態屬性,volatile保證可見性和禁止指令重排序
    private volatile static Singleton instance = null; 
    // 私有化構造器  
    private Singleton(){}   

    public static  Singleton getInstance(){   
        // 第一重檢查鎖定
        if(instance==null){  
            // 同步鎖定代碼塊 
            synchronized(Singleton.class){
                // 第二重檢查鎖定
                if(instance==null){
                    // 注意:非原子操作
                    instance=new Singleton(); 
                }
            }              
        }   
        return instance;   
    }   
}
volatile作用:以下會涉及到Java內存模型的知識

禁止指令重排序。我們知道new Singleton()是一個非原子操作,編譯器可能會重排序【構造函數可能在整個對象初始化完成前執行完畢,即賦值操作(只是在內存中開闢一片存儲區域後直接返回內存的引用)在初始化對象前完成】。而線程B在線程A賦值完時判斷instance就不爲null了,此時B拿到的將是一個沒有初始化完成的半成品。

保證可見性。線程A在自己的工作線程內創建了實例,但此時還未同步到主存中;此時線程B在主存中判斷instance還是null,那麼線程B又將在自己的工作線程中創建一個實例,這樣就創建了多個實例。

順便提一下,volatile禁止指令重排序只能保證volatile修飾的代碼之後的代碼不會在它之前執行。


轉自:https://blog.csdn.net/zcl_love_wx/article/details/80758162

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