單例模式 雙重檢查判斷 不一定安全

單例模式 雙重檢查判斷 不一定安全

雙重檢查判斷

public class Singleton {
    private static Singleton instance=null;

    private Singleton(){
    }

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

1)當線程A、B同時調用getInstance()方法,他們同時發現 instance == null成立(檢查判斷 1),同時去獲取的Singleton.class鎖
2)其中線程A獲取到鎖,線程B 處於等待狀態;線程A會創建一個SingleTon實例,之後釋 放鎖
3)線程A釋放鎖後,線程B 被喚醒,線程B獲取到鎖,然後線程B檢查
instance == null 不成立(檢查判斷2),不會再創建Singleton實例對象

編譯優化後異常

我們認爲的new Singleton()操作

  • 1)分配內存地址 M
  • 2)在內存 M 上初始化Singleton 對象
  • 3)將M的地址賦值給 instance 對象

JVM編譯優化後可能的new Singleton()操作

  • 1)分配內存地址 M
  • 2)將M的地址賦值給instance變量
  • 3)在內存M上初始化 Singleton 對象
    在這裏插入圖片描述

異常發生過程(如上圖,JVM創建new Instance()對象時先賦值再初始化)

1)線程A先執行getInstance()方法,當線程A在執行完變量的內存地址賦值(尚未初始化)時,發生線程切換,線程B獲得CPU的執行權
2)線程B在執行第一個判斷,發現 instance == null條件不成立,直接返回instance,但此時instance並沒有初始化,此時訪問instance對象的成員變量就可能發生空指針異常

解決

上述問題出現的本質原因是,JVM在編譯時的執行重排序造成的,所以只要禁止指令重排序,就可以解決這個問題,所以需要在Singleton對象的成員變量instance前加volatile關鍵字

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