轉載請標明:https://www.cnblogs.com/tangZH/p/15113505.html
一、如果一個變量被volatile關鍵字修飾,那麼所有線程都是可見的。所謂可見就是,當一條線程修改了這個變量值,新值對於其他線程來時是立即可見的; 而普通變量不能做到這一點。
1、現在計算機緩存架構:
CPU與內存之間存在緩存。
2、Java內存模型(JMM:java memory model)。
這裏的主內存再java中相當於堆。
在不同線程中操作同一個變量,實際上操作的是各自工作內存中的一個副本。
3、JMM的8大原子操作:
4、過程:
當線程1需要用到變量a的時候,會通過read操作將a讀入臨時區,然後再通過load操作載入到變量副本中。
需要用這個變量的話就用use操作。
當線程2需要用到這個變量的時候也是一樣的過程。
如果變量沒有加volatile,那麼兩個線程用到的變量實際上是不一樣的。
加上volatile之後:
會強制將緩存刷新到主內.會激活總線嗅探器。當我們改變該變量在副本里面的值後寫回主內存時,總線監聽到就會去通知其餘線程將該變量的副本移除,然後再改變主內存中的值。這樣當其他線程再次用到該變量的時候就會重新從主內存裏面拿了。
總線嗅探器機制也被叫做MESI緩存一致性協議。
二、Volatile能夠禁止指令重排。
1、先看對象的生成過程,底層的指令如下:
(1)、new 一個obj,此時內存裏面的初始值爲0.
(2)、再棧裏面生成一個引用。
(3)、執行構造方法,將值改變。
(4)、將引用指向內存。
而編譯器會進行優化,編譯器優化是指,在不改變原來語義的情況下,通過調整語句順序,來讓程序運行的更快。比如將(3)、(4)交換順序不會有什麼影響(單線程情況下)。
具體例子看:
單例模式的雙重檢測