JMM 記憶體操作指令

2022-09-13 00:06:21 字數 1676 閱讀 7754

​在上篇文章《記憶體屏障是個什麼鬼》提到了記憶體訪問的一些指令。這篇文章就來系統地介紹這些指令。

j**a 記憶體模型類似於快取記憶體與主存之間的乙個關係。

一句話解釋下什麼是 jmm:

每個執行緒執行過程中操作的記憶體,我們稱之為工作記憶體。執行緒在操作主存中共享變數時,會將變數 load 到工作記憶體,執行完操作後,還得 s**e 回主存中。

了解了jmm後,看下面一段**:

public class test 

public void seta(int a)

}

執行緒在執行看似簡單的的get/set方法時,在記憶體層面其實涉及到了相對複雜許多的記憶體操作指令。

jmm 定義了8個原子記憶體操作指令:

unlock:  作用於主存,釋放這個變數位址,其他執行緒方可共享;

read:作用於主存,將主記憶體的變數值傳輸到工作記憶體,供隨後的 load 指令使用;

load: 作用於工作記憶體, 將 read 傳輸過來的變數值賦值給本地(工作記憶體)變數副本;

use: 作用於工作記憶體,把變數的值傳給 cpu 計算單元來使用;

assign: 作用於工作記憶體,把 cpu 計算單元計算出來的值給本地變數;

store:作用於工作記憶體,把本地變數傳輸到主存,供隨後的 write 指令使用;

write:作用於主存,把 store 傳輸過來的變數值,賦值給主存中的變數副本;

重點關注 read-load 和 store-write 指令, 這四個指令涉及到工作記憶體和主存間的互動操作,記憶體屏障就是使用了這些指令。

long 和 double 的非原子操作協定

jmm 允許虛擬機器將沒有被volatile修飾的64位資料的讀寫操作劃分為兩次32位的操作來進行,即允許不同的虛擬機器來自行選擇是否要保證64位資料型別的load、store、read和write這四個操作的原子性。

非原子訪問操作,在併發環境下就有可能出現中間態的資料,既不是原值,也不是執行緒中的修改的值。

這個其實不必過於擔心,事實上,這種非原子操作基本很少見,原因有三:

主流的64位虛擬機器不會出現非原子操作,32位的x86 hotspot 有這個風險。

cpu 中整合了浮點運算器,用來專門處理浮點資料,因此,即使使用了32位的虛擬機器也不會出現非原子訪問操作風險。

hotspot 從 jdk9 開始  新增了引數 -xx:+alwaysatomicaccesses 來要求虛擬機器對所有資料型別都進行原子性的訪問。

最後如果明確知道變數存在多執行緒併發修改的情況,並且你不放心的話,就在前面加個 volatile 就是了。

原創不易,如果覺得有用,請隨手分享、在看~

JMM記憶體模型

依賴於jvm排程作業系統,由作業系統建立乙個核心執行緒klt,核心執行緒最終才會被cpu排程 jvm結構 jmm八大原子操作 volatitle如何保證可見性?匯流排鎖 當被volatitle修飾的變數想要修改主記憶體的資料時,會傳送一條帶有lock字首的彙編指令到匯流排上,此時它會鎖住匯流排,禁止...

JMM記憶體模型

mesi快取一致性協議 多個cpu從主記憶體讀取同乙個資料到各自的快取記憶體,當其中的乙個cpu修改了快取裡的資料,該資料會馬上同步回主記憶體,其它cpu通過匯流排嗅探機制可感知到資料的變化從而將自己快取裡的資料失效 lock unlock 匯流排加lock變成序列,效率降低 store前加lock...

java記憶體模型 JMM

1 原子性 atomicity 不可中斷的操作,即使是多個執行緒一起執行的時候,也不會被其他執行緒干擾 2 可見性 visibility 當乙個執行緒修改了某乙個共享變數的值,其他執行緒是否能夠立即知道這個修改 3 有序性 ordering 重排指令可以保證序列語義一致,但沒有義務保證多執行緒之間的...