雙重檢驗的單例模式,為什么要用volatile關鍵字


雙重檢驗的單例模式是比較推薦的單例寫法,在該代碼中的單例對象的是用volatile關鍵字修飾的。這時就產生的一個疑問,為什么需要volatile來修飾呢?
上網查看多個博客,下面簡單通俗分析一下當中的原因:
貼上不加volatile單例代碼

public class Singleton {
    private static Singleton s;
    private Singleton(){};
    public static Singleton getInstance() {  //1
        if(s == null) { //2
            synchronized (Singleton.class) { //3
                if(s == null) { //4
                    s = new Singleton(); //5
                }
            }
        }
        return s; //6
    }
}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

以前不了解為什么需要volatile關鍵字,后來發現在並發情況下,如果沒有volatile關鍵字,在第5行會出現問題
對於第5行 s = new Singleton(); //5
可以分解為3個步驟:

1 memory=allocate();// 分配內存 相當於c的malloc
2 ctorInstanc(memory) //初始化對象
3 s=memory //設置s指向剛分配的地址

上面的代碼在編譯器運行時,可能會出現重排序 從1-2-3 排序為1-3-2

如此在多線程下就會出現問題

例如現在有2個線程A,B

線程A在執行第5行代碼時,B線程進來,而此時A執行了 1和3,沒有執行2,此時B線程判斷s不為null 直接返回一個未初始化的對象,就會出現問題

而用了volatile,上面的重排序就會在多線程環境中禁止,不會出現上述問題。
正確雙重檢驗單例模式寫法:

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

總結:加上volatile就是為了防止產生指令的重排序問題
為什么volatile能禁止指令的重排序呢?這里就涉及到volatile的原理了,這里就不多說volatile的原理,可以看看海子大神的博客:volatile關鍵字解析
---------------------
作者:Tuzki_小辣雞
來源:CSDN
原文:https://blog.csdn.net/weixin_37659242/article/details/82776198
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM