1. 程式人生 > >java多執行緒之記憶體可見性

java多執行緒之記憶體可見性

可見性:一個執行緒對共享變數值的修改,能夠及時地被其他執行緒看到。

共享變數:如果一個變數在多個執行緒的工作記憶體中都存在副本,那麼這個變數就是幾個執行緒的共享變數。 

e.g:主記憶體當中有一個變數x,多個執行緒同時包含有一個x的副本,當某個執行緒的工作的x值改變的時候要及時地被執行緒看到。就會一個問題,多個執行緒之間如何做到拿到的正確的x

+ 原理是:
  1. 把工作記憶體1中更新過的共享變數重新整理到主記憶體中
  2. 將主記憶體中最新的共享變數的值更新到工作記憶體2中 
多執行緒之間使用共享變數並不能保證共享變數的可見性(指令重排序,執行的不確定性),所以在java中有一種方式是使用synchronize(原子性,可見性) 步驟:(關鍵在於解鎖前要把工作記憶體中的資料刷到主記憶體中,加鎖時,將清空工作記憶體中的共享變數,加鎖後一定要從主記憶體中重新獲取資料)
  1. 獲取互斥鎖
  2. 清空工作記憶體
  3. 從主記憶體拷貝最新副本到本地工作記憶體中
  4. 執行程式碼
  5. 將更改後的共享變數重新整理到主記憶體中
  6. 釋放鎖
Synchronized實際是實現的一種鎖的機制,在一段操作和記憶體進行加鎖,同一時刻只有一個執行緒才能進入鎖內,鎖內無論怎麼重排序執行結果都是一樣的。synchronized同時可以保證可見性 還有一種方式是使用volatile來修飾共享變數
  • 對volatile變數執行寫操作時,會在寫操作後加入一條store屏障指令
  • 對volatile變數執行讀操作時,會在讀操作前加入一條load屏障指令
volatile變數在每次被執行緒訪問時,都強迫從主記憶體中重讀該變數的值,而當該變數發生變化時,又會強迫執行緒將最近的值重新整理到主記憶體。這樣任何時刻,不同執行緒總能看到該變數的最新值。 volatile不能保證volatile變數複合操作的原子性:

synchronized和volatile區別:
  • volatile 不需要加鎖,比synchronized更輕量級,不會阻塞執行緒。
  • 從記憶體可見性角度,volatile讀相當於加鎖,volatile寫相當於解鎖
  • synchronized既能保證可見性,又能保證原子性,而volatile只能保證可見性,無法保證原子性。
指令重排序