volatile在Java內存模型(JMM)中,保證共享變量對全部線程可見,但不保證原子性。volatile語義是同步,經過共享變量的方式,完成線程間的通訊。
html
Java內存模型中抽象、簡化了計算機物理設備,分紅工做內存和主內存,線程有各自的工做內存,卻共享主內存。若是要把Java內存模型與物理設備映射起來的話,L1,L2 Cache能夠視爲工做內存,而L3 Cache視爲主內存。線程執行指令時,會優先選擇距離 CPU 較近的位置的工做內存中使用,而不會從讀寫速度較慢的主內存中,我稱之爲「就近原則」。當線程指令執行完後,賦值給工做內存,若是不回寫到主內存,或者通知其餘線程,其餘線程是沒法知曉變量已經修改,仍然會使用曾經緩存在工做內存中的變量,這就形成了緩存不一致的問題,Java使用volatile解決這種問題。volatile保證指令賦值完後的變量當即同步回主內存中,聲明並通知其餘線程當前賦值的變量已經失效,其餘線程在下次使用時會放棄工做內存中變量,使用主內存中的變量。這樣就完成了線程間對於volatile修飾的變量的通訊。java
執行引擎只與工做內存交互,再有工做內存與主內存交互。站在執行引擎的角度,與工做內存操做完成即表示指令執行完,可是何時工做內存會將結果刷新回主內存卻不可預測。Java線程間的通訊是經過共享內存的方式,線程A若是想通知其餘全部線程(線程B,線程C)對於變量f的變化狀況,須要知足兩點:編程
可見性的語義是線程對變量更新操做後,其餘線程是能夠獲知變量的變動狀況。
緩存
原子操做是一個或多個不可中斷的操做,要麼一次性徹底執行完畢,要麼就不執行,最終狀態不存在有些操做執行完,有些操做沒有執行,在外部看來是不可分割的總體(好比化學中的原子,固然原子也是能夠再分割的,不過站在分子層面,原子是最小的不可分割的),原子操做關注的是不被線程調度器中斷的操做。安全
原子性操做是不會出現線程交替執行的狀況,若是出現線程交替,則說明操做被線程調度器中斷。在Java內存模型中,原子性保證你獲取的變量要麼是初始值,要麼是被某一個線程寫入的值,而不會是有多個線程同一時間寫入而產生的混亂結果,long或double類型除外(由於變量的前32位可能由一個線程寫入,後32位由另外一個不一樣的線程寫入),不過加上volatile修飾後的long 和double也具備原子性。併發
注意:volatile關注可見性,而與原子性沒有關係。volatile關注點在於從工做內存刷新回主內存,而原子操做關注的是否不被打斷。原子和同步目的都是讓不一樣線程能夠安全地訪問共享變量的兩種處理方式,避免形成內存一致性錯誤。oracle
我是葛一凡,但願對你有幫助。post