一文讀懂volatile

行走在鍵盤上俠客 發佈 2022-05-20T11:29:09.641040+00:00

volatile 變量修飾的共享變量進行寫操作前會在彙編代碼前增加 lock 前綴:1),將當前處理器緩存行的數據寫回到系統內存;2),這個寫會內存的操作會使其它 cpu 緩存該內存地址的數據無效。

volatile 變量修飾的共享變量進行寫操作前會在彙編代碼前增加 lock 前綴:

1),將當前處理器緩存行的數據寫回到系統內存;

2),這個寫會內存的操作會使其它 CPU 緩存該內存地址的數據無效。


Java 語言 volatile 關鍵字可以用一句貼切的話來描述 「 人皆用之,莫見其形 「。理解 volatile 對理解它對理解 Java 的整個多線程的機制非常有幫助。


JVM 內存結構中有一個非常重要的內存區域叫做線程棧 , 每個線程的棧大小可以通過設置 JVM 參數-Xss, -Xss128k 表示每個線程堆棧大小為 128K,JDK1.5 默認值為 1M。


線程棧內存存儲了基本類型變量和對象引用,當訪問了對象的某一實例變量時,通過在棧中獲得對象引用再獲取變量的值,然後將變量的值拷貝至線程的工作內存。


每個線程 (處理器) 都有工作內存,工作內存存了該線程以讀寫共享變量的副本。工作內存是 JMM 抽象概念 , 並不真實存在。


它涵蓋了緩存、寫緩衝區、寄存器和其它硬體和編譯器優化。


1),read and load 從主存複製變量到當前工作內存;

2),use and assign 執行代碼,改變共享變量值;

3),store and write 用工作內存數據刷新主存相關內容;

4),其中 use and assign 可以多次出現。


但是這一些操作並不是原子性,也就是在 read load 之後,如果主內存 count 變量發生修改之後,線程工作內存中的值由於已經加載,不會產生對應的變化,所以計算出來的結果會和預期不一樣。


可見性指的是一個線程對變量的寫操作對其他線程後續的讀操作可見。


由於現代 CPU 都有多級緩存,CPU 的操作都是基於高速緩存的,而線程通信是基於內存的,這中間有一個 Gap, 可見性的關鍵還是在對變量的寫操作之後能夠在某個時間點顯示地寫回到主內存,這樣其他線程就能從主內存中看到最新的寫的值。volatile,synchronized(隱式鎖), 顯式鎖,原子變量這些同步手段都可以保證可見性。可見性底層的實現是通過加內存屏障實現的:

1),寫變量後加寫屏障,保證 CPU 寫緩衝區的值強制刷新回主內存;

2),讀變量之前加讀屏障,使緩存失效,從而強制從主內存讀取變量最新值。

總結: 在並發環境保證有序性、可見性,但原子性沒辦法保證

關鍵字: