Java多執行緒之共享變數的記憶體不可見性
共享變數的記憶體不可見性
多執行緒的記憶體模型
執行緒獨有的工作記憶體(執行緒快取 = > 提高工作效率)——所有執行緒共享的主記憶體
執行緒讀取在主記憶體的成員變數,即共享變數的過程:
-
- 執行緒的工作記憶體會去讀取主記憶體的成員變數並儲存副本
- 執行緒在工作記憶體中修改副本
- 將修改後的副本的值推送給主記憶體並改寫主記憶體中該變數的值
- 主記憶體成員變數修改後的值不會主動推給其他執行緒(各執行緒的記憶體獨有),這就會造成執行緒的工作記憶體的共享變數的不同步
現有問題:各個執行緒的工作記憶體不可見
描述:A執行緒讀取了共享變數num,此時B執行緒修改了共享變數為num+1,並推送給主記憶體改寫,但是主記憶體不會主動推送給A執行緒,於是A和B的共享變數就會出現不同步!
解決方法:synchronized(同步程式碼塊/同步方法=> 加鎖 同步共享變數 ) 、volatile => 同步共享變數
volatile: Java關鍵字使得主記憶體的共享變數每經過一次修改都會推送給其他執行緒,讓其他執行緒修改其工作記憶體中的副本!
synchronized 與 volatile的區別 / 不同點
-
volatile 是輕量級的同步策略,用於修飾基本型別的變數;
synchronized 是重量級的同步策略,基於物件的同步鎖=> 鎖的是物件/Class
-
volatile 不具備互斥性,多個執行緒可以同時訪問共享變數;
synchronized 是互斥鎖,具備互斥性,在加鎖的同步程式碼塊中只能有一個執行緒訪問共享變數;
-
volatile不能保證變數的原子性,即一組對共享變數的操作不具備事務 => 要麼全部完成,要麼全部不完成!
synchronized 可以保證變數的原子性,即在被鎖的程式碼塊中只能允許一個執行緒去執行對共享變數的操作,其他需要執行這組操作的執行緒會進入阻塞狀態,等待當前執行緒完成並釋放鎖。
記憶體不可見的本質:執行緒之間有互相獨立的快取區,當多個執行緒對共享資料進行操作時,其操作彼此不可見!
使用volatile之後 ,所有執行緒對共享變數的操作都相當於在主記憶體中完成,即不再存在操作的不可見,此時所有執行緒操作的變數位於主記憶體
本文來自部落格園,作者:{夕立君},轉載請註明原文連結: