volatile語義



volatile在Java內存模型(JMM)中,保證共享變量對所有線程可見,但不保證原子性。volatile語義是同步,通過共享變量的方式,完成線程間的通信。

為什么需要volatile

Java內存模型中抽象、簡化了計算機物理設備,分成工作內存和主內存,線程有各自的工作內存,卻共享主內存。如果要把Java內存模型與物理設備映射起來的話,L1,L2 Cache可以視為工作內存,而L3 Cache視為主內存。線程執行指令時,會優先選擇距離 CPU 較近的位置的工作內存中使用,而不會從讀寫速度較慢的主內存中,我稱之為“就近原則”。當線程指令執行完后,賦值給工作內存,如果不回寫到主內存,或者通知其他線程,其他線程是無法知曉變量已經修改,仍然會使用曾經緩存在工作內存中的變量,這就造成了緩存不一致的問題,Java使用volatile解決這種問題。volatile保證指令賦值完后的變量立即同步回主內存中,聲明並通知其他線程當前賦值的變量已經失效,其他線程在下次使用時會放棄工作內存中變量,使用主內存中的變量。這樣就完成了線程間對於volatile修飾的變量的通信。

可見性

執行引擎只與工作內存交互,再有工作內存與主內存交互。站在執行引擎的角度,與工作內存操作完成即表示指令執行完,但是什么時候工作內存會將結果刷新回主內存卻不可預測。Java線程間的通信是通過共享內存的方式,線程A如果想通知其他所有線程(線程B,線程C)對於變量f的變化情況,需要滿足兩點:

  1. 將變量回寫到主內存中
  2. 執行引擎讀取時強制從主內存中加載
    在增加了增加了L1、L2 Cache之后,CPU何時將變量從獨享緩存刷新會共享內存,獨享緩存是否從共享內存加載變量,時間上都是不可確定的,這就造成了緩存不一致的問題。

可見性的語義是線程對變量更新操作后,其他線程是可以獲知變量的變更情況。
工作內存和主內存關系工作內存和主內存關系

原子性

原子操作是一個或多個不可中斷的操作,要么一次性完全執行完畢,要么就不執行,最終狀態不存在有些操作執行完,有些操作沒有執行,在外部看來是不可分割的整體(比如化學中的原子,當然原子也是可以再分割的,不過站在分子層面,原子是最小的不可分割的),原子操作關注的是不被線程調度器中斷的操作。

原子性操作是不會出現線程交替執行的情況,如果出現線程交替,則說明操作被線程調度器中斷。在Java內存模型中,原子性保證你獲取的變量要么是初始值,要么是被某一個線程寫入的值,而不會是有多個線程同一時間寫入而產生的混亂結果,long或double類型除外(因為變量的前32位可能由一個線程寫入,后32位由另一個不同的線程寫入),不過加上volatile修飾后的long 和double也具有原子性。

注意:volatile關注可見性,而與原子性沒有關系。volatile關注點在於從工作內存刷新回主內存,而原子操作關注的是否不被打斷。原子和同步目的都是讓不同線程可以安全地訪問共享變量的兩種處理方式,避免造成內存一致性錯誤。

我是葛一凡,希望對你有幫助。

參考

  1. 聊聊並發(一)深入分析Volatile的實現原理
  2. 聊聊並發(五)——原子操作的實現原理
  3. Java Language Specification
  4. Java Volatile 關鍵字詳解
  5. 從緩存行出發理解volatile變量、偽共享False sharing、disruptor
  6. Java並發編程:volatile關鍵字解析
  7. Java 編程要點之並發(Concurrency)詳解
  8. Java 並發編程(1): Java 內存模型(JMM)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM