volatile關鍵字

     咱們都知道 volatile這個關鍵字,使用它在多線程環境下能保證該變量的內存可見性;這是如何實現的呢?Java編程語言容許線程訪問共享變量,爲了確保共享變量能被準確和一致地更新,線程應該確保經過排他鎖單獨得到這個變量。Java語言提供了volatile,在某些狀況下比鎖要更加方便。若是一個字段被聲明成volatile,Java線程內存模型確保全部線程看到這個變量的值是一致的。
其具體實現仍是須要靠底層硬件和指令層面的支持:
帶有這個關鍵字修飾的變量,在進行寫操做的時候,彙編指令會增長一個「lock」操做,該操做的影響以下,
  將當前處理器緩存的該變量的值寫回到主內存,更新主內存變量的「版本號」;其餘處理器內緩存的變量「版本號」 和主內存不一致致使失效。這麼作的目的就是保證任什麼時候刻讀取到的該變量都是最新值。
     而,volatile這個關鍵字還有另一個功能,那就是限制指令重排。
  所謂「重排」,就是指編譯器和處理器爲了優化程序性能而對指令序列進行從新排序的一種手段。在JVM的實現裏,重排有必定的原則:編譯器和處理器可能會對操做作重排序。編譯器和處理器在重排序時,會遵照數據依賴性,編譯器和處理器不會改變存在數據依賴關係的兩個操做的執行順序。 這裏所說的數據依賴性僅針對單個處理器中執行的指令序列和單個線程中執行的操做,不一樣處理器之間和不一樣線程之間的數據依賴性不被編譯器和處理器考慮。JMM針對編譯器指定的volatile重排序規則以下:
 
·當第二個操做是volatile寫時,無論第一個操做是什麼,都不能重排序。這個規則確保 volatile寫以前的操做不會被編譯器重排序到volatile寫以後。
·當第一個操做是volatile讀時,無論第二個操做是什麼,都不能重排序。這個規則確保 volatile讀以後的操做不會被編譯器重排序到volatile讀以前。
·當第一個操做是volatile寫,第二個操做是volatile讀時,不能重排序。
爲了實現volatile的內存語義,編譯器在生成字節碼時,會在指令序列中插入內存屏障來禁止特定類型的處理器重排序。對於編譯器來講,發現一個最優佈置來最小化插入屏障的總數幾乎不可能。爲此,JMM採起保守策略。
下面是基於保守策略的JMM內存屏障插入策略。·在每一個volatile寫操做的前面插入一個StoreStore屏障。
·在每一個volatile寫操做的後面插入一個StoreLoad屏障。
·在每一個volatile讀操做的後面插入一個LoadLoad屏障。
·在每一個volatile讀操做的後面插入一個LoadStore屏障。
相關文章
相關標籤/搜索