天天看點

[Java學習] 單例模式餓漢式雙檢鎖/雙重校驗鎖中的volatile

首先我們先來看看單例模式餓漢式中的雙檢鎖代碼,這裡我們用的是菜鳥教程的資料。

代碼連結:https://www.runoob.com/design-pattern/singleton-pattern.html

雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)
JDK 版本:JDK1.5 起
是否 Lazy 初始化:是
是否多線程安全:是
實作難度:較複雜
描述:這種方式采用雙鎖機制,安全且在多線程情況下能保持高性能。getInstance() 的性能對應用程式很關鍵。

執行個體

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

我們可以看到第二行中有個volatile 的關鍵字,那麼volatile 有啥用呢?這時候我們要先了解在java中通過new的方式建立對象的過程的具體步驟

[Java學習] 單例模式餓漢式雙檢鎖/雙重校驗鎖中的volatile

在通過new建立對象時有三個步驟:

  1. 配置設定記憶體空間
  2. 初始化對象
  3. 将記憶體空間的位址指派給對應的引用

但是這個操作是非原子性操作,啥意思?就是說它不是一個整體操作,它的執行順序是能被打亂的

可能就成了這樣:

[Java學習] 單例模式餓漢式雙檢鎖/雙重校驗鎖中的volatile

為什麼會出現這種情況呢?是因為JVM在加載目前操作的時候是由指令來執行這些代碼的,也就是這些代碼會被翻譯成一個一個的指令剛才的三步就是三個指令。指令執行要有順序,但是jvm執行預設的時候是沒有順序的。但是這個亂序機率發生的機率非常非常的低,正常情況在是不會發生的但是要是在運作過程中電腦卡機了就可能發生cup被搶導緻了正在執行的指令被搶。是以我們有個指令重排的概念,什麼是指令重排?簡單點剛才我們指令順序混亂就是指令重排,而volatile的作用就是能禁止指令重排,也就是會讓jvm必須按123的順序執行。

[Java學習] 單例模式餓漢式雙檢鎖/雙重校驗鎖中的volatile

是以不加volatile 正常情況下不會發生問題,但是仍有極小機率會出事,保險起見還是加了吧。

當然,我講的比較淺,個人又比較菜,還在學習中,我覺得我還可以搶救一下,有錯的地方多多包容一下,請幫我指正,想再深入的小夥伴可以搜尋下volatile的原理