java 的記憶體模型(Java Memory Model)
改變執行順序
編譯器、JVM 或者 CPU 共同努力通過改變執行順序來最求程式的執行效率。
我們通常coding 時候,程式碼的執行是有一定順序,這樣保證我們可以完成一定邏輯,但是在 JVM 執行程式碼會根據需要,也就是最求效能來調整我們程式碼執行順序。
但是這樣調整順序並不會影響程式執行的結果。
a = 3 b = 2 a = a + 1;
這是上面程式碼的 JVM 執行的情況,我們載入 a 然後為 a 進行賦值,然後將其儲存到記憶體中,同樣操作在下兩條語句。
Load a Set to 3 Store a Load b Set to 2 Store b Load a Set to 4 Store a
我們發現執行過程中 load a 被執行了兩次,我們需要對此進行優化。具體優化如下
a = 3 a = a + 1 b = 2
Load a Set to 3 set to 4 Store a Load b Set to 2 Store b
這些具體優化工作是 JVM 中完成的。
可見性
多執行緒的中一致性的表現,又叫做併發

007.JPG
我們看最上面一層 core 這裡表示有 4 個 cpu,每一個 cpu 都有一個 registers(註冊機),然後就是 L1 cache 一級快取,雖然不大因為 cpu 直接從這裡讀取記憶體所以這裡非常快。然後就是 L2 二級快取這裡就是兩個 core 來共享的。到了 3L 快取就是所有 core 共享的記憶體區域。離 cpu 越遠的快取會訪問速度降低同時容量變大。
public class FieldVisibility{ int x = 0; public void writerThread(){ x = 1 } public void readerThread(){ int r2 = x; } }
這裡建立一個 FieldVisibility 類,初始化 x = 0,讓後提供兩個方法分別在不同的執行緒對 x 進行讀寫操作。

008.JPG
然後建立兩個 FieldVisibility 的例項分別呼叫讀和寫方法來讀寫 x。

009.JPG
當我們一個例項呼叫 writerThread 方法來修改 x 的值為 1,x = 1 僅會儲存在 local cache 本地快取,而不會更新到 shared cache (共享快取),所以當另一個例項呼叫 readerThread 來獲取 x 的值,依舊得到是 0 而不是 1.
這就是欄位可見性問題。
public class FieldVisibility{ volatile int x = 0; public void writerThread(){ x = 1 } public void readerThread(){ int r2 = x; } }

010.JPG
當我們用關鍵字 volatile 修飾字段 x 時,當 x 發生變化會更新共享快取,這樣就保證 x 的更改對其他方法可見性。

011.JPG