Java volatile 怎麼保證不被指令重排序優化
阿新 • • 發佈:2019-02-17
記憶體間互動操作
- lock: 作用主記憶體
- unlock: 作用主記憶體
- read/load:這兩個操作順序執行,不能單獨出現;主記憶體的變數=>工作記憶體的變數
- use: 作用工作記憶體,把工作記憶體變數傳給執行引擎
- assign: 作用工作記憶體,把執行引擎收到的值賦給工作記憶體變數
- store/write: 這兩個操作順序執行;不能單獨出現;工作記憶體的變數=>主記憶體的變數
通過主記憶體與工作記憶體互動來理解這些操作:
注意:
- 不允許
工作記憶體
直接使用未初始化的變數
記憶體模型的3個特徵
- 原子性
- 有序性, 同一個執行緒內觀察是有序, 一個執行緒觀察另一個執行緒的操作是無序的
- 可見性
重排序
如下程式碼,由於threadA對於threadB是無序的,對A重排序優化,②可能提前執行,這就導致threadB跳過④
ThreadA {
do something //①
set flag = true//②
}
ThreadB {
if(flag){ //③
do something //④
}
}
通過volatile,synchronized可以禁止重排序優化
happens-before(hb)
意義:記憶體模型通過hb原則併發操作過程中的有序性問題
actionA先行發生actionB,就是說A對B可見(A的結果在B執行時可見)
- 執行緒啟動/終結規則
- volatile規則, volatile變數寫操作hb後面讀操作
- lock規則, unlock hb lock
- Order規則, 執行緒內書寫前面的操作hb書寫後面的操作
- 中斷規則, Thread.interrupt hb 被中斷程式檢測到的中斷事件的發生
- 傳遞性
volatile禁止重排序原理
如下圖,1、2保證可見性,3禁止重排序
- 1.A動作之前必關聯P、F動作
- 2.B動作自後必然伴隨G、Q動作
- 3.A優先於B,則P優先於Q(這個比較顯然);B優先於A,則Q優先於P
例如:執行緒B對變數flag=true同步優先於A執行緒使用