JMM Java 內存模型
-
定義程序中各個變量的訪問規則,即變量是如何存入內存、如何從內存取出的;
變量包括:實例字段、靜態字段、構成數組對象的元素,但不包括線程私有的局部變量和方法參數(不會被共享,也就不存在競爭問題)
-
工作內存與主內存
- 所有的變量都存在主內存中
- 每條線程有自己獨立的、相互隔離的工作內存,保存了被該線程使用的變量的主內存副本拷貝;線程對變量的所有操作都必須在工作內存進行,不能直接讀寫主內存的變量
- 線程間變量值的傳遞均需要通過主內存來完成
-
內存間交互操作
- 操作規則:
- 不允許
read
和load
、store
和write
操作之一單獨出現;從主內存讀取的變量必須要裝載到工作內存、工作內存發起存儲的變量必須要寫入主內存 - 不允許一個線程丟棄最近的
assign
操作;變量改變了必須同步到主內存 - 不允許一個線程在未發生任何
assign
操作時,把數據從線程的工作內存同步到主內存 - 新變量只能在主內存中產生,不允許在工作內存中直接使用一個未
load
或assign
的變量 - 一個變量同一時刻只允許一條線程對其進行
lock
操作 - 對一個變量執行
lock
操作,會清空工作內存中此變量的值;使用這個變量前,需重新load
或assign
初始化變量的值 - 變量沒有
lock
則不允許unlock
- 對一個變量執行
unlock
操作前,必須先把次變量同步回主內存(store
和write
操作)
- 不允許
- volatile 變量的特殊規則
- 對所有線程的可見性
- 對 volatile 變量所有的寫操作都能立即反應到其他線程之中(每次使用之前都要先刷新)
- 線程內有序性,禁止指令重排序
- 線程內表現為串行的語義 (Within-Thread As-If-Serial Semantics)
- 在本地代碼中插入許多內存屏障指令來保證處理器不發生亂序執行
- 只有原子操作才是并發安全的
-
i++;
典型場景
-
- 對所有線程的可見性
- long 和 double 型變量的特殊規則
- 運行虛擬機將沒有被 volatile 修飾的 64 位數據的讀寫操作劃分為兩次 32 位的操作來進行;非原子性協定(Nonatomic Treatment of double and long Variables)
- 多線程可能會出現半個變量的情況(非常罕見)
- 實際開發中多數虛擬機都把 64 位數據的讀寫操作作為原子操作對待
- 操作規則:
關鍵字 | 原子性 | 可見性 | 有序性 |
---|---|---|---|
synchronized | √ | √ | √ |
volatile | × | √ | √ |
final | - | √ | - |
參考
- wiki
- specs
- 深入理解 Java 虛擬機 第 12 章 Java 內存模型與線程