疏漏總結(二)——volatile

volatile是面試中常常被問到的,現在來總結一下volatile的關鍵地方。

volatile是如何實現禁止指令重排的???

先來說一下什麼是指令重排:

int m = 1;
int n = 1;

JVM中的順序可能是先執行初始化n,再初始化m,這個就叫做指令重排。

爲何JVM要進行指令重排?

指令重排就初衷就是在代碼不改變執行的結果的情況下改變代碼執行的順序,這個執行層面是操作系統級別的,不是簡單的JVM,可以理解爲是CPU操作JVM字節碼的時候的一個操作。

指令重排是帶來什麼??

單線程情況下不是很明顯,多線程情況下必然會產生一定的問題。

volatile和cpu指令重排有什麼關係?

被volatile修飾的變量會禁止指令重排,中間有個內存屏障使屏障前後的指令不會發生順序的變化。

volatile如何做到禁止指令重排的?

內存屏障:內存屏障稱爲內存柵欄或柵欄指令是一種屏障指令,它使cpu或編譯器對屏障指令之前的之後發出的內存操作執行一個排序約束。這通常意味着在屏障之前發佈的操作被保證在屏障之後發佈的操作之前執行。

內存屏障的種類???

一共有四種:
(1)LoadLoad屏障
抽象場景:Load1;LoadLoad;Load2
Load1和Load2代表兩條讀取指令。在Load2要讀取的數據被訪問前,保證Load1要讀取的數據被讀取完畢。

(2)StoreStore屏障
抽象場景:Store1;StoreStore;Store2
Store1和Store2代表兩條寫入指令。在Store2寫入執行前,保證Store1的寫入操作對其它處理器可見。

(3)LoadStore屏障
抽象場景:Load1;LoadStore;Store2
在Store2被寫入前保證Load1要讀取的數據被讀取完畢。

(4)StoreLoad屏障
抽象場景:Store1; StoreLoad; Load2
Load2讀取操作執行前,保證Store1的寫入對所有處理器可見。StoreLoad屏障的開銷是四種屏障中最大的。

當一個變量被volatile修飾之後從JVM層面會對這個變量做兩件事情:
<1>每個volatile寫操作前插入StoreStore屏障,寫操作後插入StoreLoad屏障
<2>每個volatile讀操作前插入LoadLoad屏障,讀操作後插入LoadStore屏障

因此可以證明volatile除可見性外的另一個特性:阻止編譯時和運行時的指令重排,編譯時JVM編譯器遵循內存屏障的約束,運行時候依靠cpu屏障來阻止重排。

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