1. 程式人生 > >JVM(二)---記憶體模型,可見性,指令重排序

JVM(二)---記憶體模型,可見性,指令重排序

1.記憶體模型
收修庵我們思考一下java執行緒要向另一個執行緒進行通訊,應該怎麼做,我們再把需求明確一點,一個java執行緒對一個變數的更新怎麼通知到另外一個執行緒呢?我們知道java的例項物件、陣列元素都存放在java堆中,java堆是執行緒共享的。java堆稱為主記憶體,每一個執行緒自己私有的工作空間稱為工作記憶體,如果執行緒1 向執行緒2通訊一定會經過型別的流程:
這裡寫圖片描述

1.執行緒1將自己工作記憶體中X更新為1重新整理到主記憶體中
2.執行緒2從主記憶體讀取變數X=1,更新到自己的工作記憶體中,從而執行緒2讀取的就是執行緒1更新的值
2.可見性
java中有一個關鍵字volatile,它有什麼用呢?這個答案其實在上述java執行緒機制中。由於工作記憶體這個中間層的出現,執行緒1和執行緒2必然存在延遲的問題,例如執行緒1在工作記憶體中更新了變數,但還沒重新整理到主記憶體,而此時執行緒2獲取到的變數值就是未更新的變數值,又或者執行緒1成功將變數更新到主記憶體,但執行緒2依然使用自己工作記憶體中的變數值,同樣會出問題。
但這一切等到volatile出現後, 再也不是問題,volatile保證兩件事:
1.執行緒1工作記憶體中的變數更新會強制立即寫入到主記憶體
2.執行緒2工作記憶體中的變數會強制立即失效,這使得執行緒2必須去主記憶體中獲取最新的變數值
所以這就理解了volatile保證了變數的可見性,因為執行緒1對變數的修改能第一時間讓執行緒2可見。
3.指令重排序

關於指令排序我們先看一段程式碼

int a = 0;boolean flag = false;
//執行緒1
public void writer(){
a = 1;
flag = true;
}
//執行緒2
public void reader(){
 if(flag){
 int i = a+1;
 }
}

執行緒1依次執行 a = 1,flag =true; 執行緒2判斷到flag = true後,設定i =a+1,根據程式碼語義,我們可能會腿短此時i的值等於2,但事實情況不一定如此,引起這個問題的原因是執行緒1內部的兩條語句a=1;flag = true 可能被重新排序執行。
這就是指令重新排序的簡單演示。
不會被重新排序的邏輯
(1)寫後讀:a=1;b=a;
(2)寫後寫:a=1;a=2;
(3)讀後寫:a=b;b=1;