1. 程式人生 > 其它 >多執行緒的共享變數的記憶體不可見性

多執行緒的共享變數的記憶體不可見性

執行緒的開銷 :
  • 執行緒的建立和銷燬
  • 執行緒的上下文切換和排程
  • 執行緒的同步
多執行緒的記憶體模型: 執行緒獨有的工作記憶體(執行緒快取用於提高效率)---------所有執行緒共享的主記憶體

執行緒讀取在主記憶體的成員變數(即共享變數)的過程:

  1. 執行緒的工作記憶體會去讀取主記憶體的成員變數並儲存副本
  2. 執行緒在工作記憶體中修改副本
  3. 將修改後的副本的值推送給主空間並改寫主空間該成員變數的值
  4. 主空間成員變數修改後的值將不會主動推送給其他執行緒, 這就造成了執行緒的工作記憶體的共享變數的不同步
問題: 各個執行緒的工作記憶體不可見
  即 A執行緒先讀取共享變數a, B執行緒修改了共享變數a後為a`,推送給主記憶體並改寫, 主記憶體不會推送給A執行緒,A和B的變數會不同步

解決辦法

  • synchroized可以同步值
  • volatile關鍵字 會使得主記憶體的共享變數每經過一次改變都會推送給其他的執行緒, 其他執行緒會修改其副本

同步值之synchronized和volatile的區別
相同點:
  synchronized 和 volatile都能用來同步共享變數
不同點:
  1. volatile是輕量級的同步策略, 可以修飾基本型別的變數,如int, synchronized是重量級的同步策略,基於物件的同步鎖
  2. volatile不具備互斥性, 一個執行緒訪問共享變數 , 其他執行緒也可以訪問共享變數
    synchronized是互斥鎖, 具備互斥性, 在被鎖的程式碼塊上只能有一個執行緒訪問共享變數



  3. volatile不能保證變數的原子性, 即一組對共享變數的操作不具備事務(要麼全部完成,要麼全部不完成) 如 i++/i--
即一個執行緒在進行一組操作中還沒完成時, 其他執行緒也能進入這組操作對共享變數進行修改
而 synchronized則能保證一組對共享變數操作的原子性, 即這組操作全部完成,才能進行下一輪操作
即在被鎖的程式碼塊中只能允許一個執行緒去執行這組操作, 其他需要執行這組操作的執行緒會進入阻塞狀態,等待其完成

總結:

主記憶體    工作記憶體
共享變數   副本
工作記憶體中會主動去拉取主記憶體的共享變數並建立其副本


工作記憶體中的副本修改後會推送給主記憶體改寫共享變數
volatile 會使得主記憶體修改後的共享變數推送其他執行緒

記憶體不可見的本質 : 執行緒之間有互相獨立的快取區, 當多個執行緒對共享資料進行操作時, 其操作彼此不可見

可以直接理解: 使用volatile之後該共享該變數執行緒不在工作記憶體快取其副本, 所有執行緒對該變數的操作全是在主記憶體中完成
即不在存在操作的不可見,所有執行緒的操作的變數是位於主記憶體的變數

https://www.cnblogs.com/huangleshu/p/10026222.html