「溫故知新-《Java并發(fā)編程的藝術(shù)》讀書筆記」volatile實(shí)現(xiàn)原理

volatile 的定義與實(shí)現(xiàn)原理

Java語言規(guī)范第3版中對(duì)volatile的定義如下:Java編程語言允許線程訪問共享變量,為了確保共享變量能被準(zhǔn)確和一致地更新,線程應(yīng)該確保通過排他鎖單獨(dú)獲得這個(gè)變量。 Java 語言提供了volatile,在某些情況下比鎖要更加方便。如果一個(gè)字段被聲明成volatile, Java 線程內(nèi)存模型確保所有線程看到這個(gè)變量的值是一致的。
volatile 是如何來保證可見性的呢? 讓我們?cè)?X86 處理器下通過工具獲取JIT 編譯器生成的匯編指令來查看對(duì) volatile 進(jìn)行寫操作時(shí),CPU 會(huì)做什么事情。Java 代碼如下。
//instance 是 volatile 變量
instance = new Singleton();
轉(zhuǎn)變成匯編代碼,如下。
0x0la3deld: movb 50 x0,0X1104800 (tesi) ;0x01a3de24: lock agdl sox0, (esp) ;
有 volatile 變量修飾的共享變量進(jìn)行寫操作的時(shí)候會(huì)多出第二行匯編代碼,通過查 IA-32架構(gòu)軟件開發(fā)者手冊(cè)可知,Lock 前綴的指令在多核處理器下會(huì)引發(fā)了兩件事情。
1)將當(dāng)前處理器緩存行的數(shù)據(jù)寫回到系統(tǒng)內(nèi)存
2)這個(gè)寫回內(nèi)存的操作會(huì)使在其他 CPU 里緩存了該內(nèi)存地址的數(shù)據(jù)無效
為了提高處理速度,處理器不直接和內(nèi)存進(jìn)行通信,而是先將系統(tǒng)內(nèi)存的數(shù)據(jù)讀到內(nèi)部緩存(L1,L2 或其他)后再進(jìn)行操作,但操作完不知道何時(shí)會(huì)寫到內(nèi)存。如果對(duì)聲明了volatile 的變量進(jìn)行寫操作,JVM 就會(huì)向處理器發(fā)送一條 Lock 前綴的指令,將這個(gè)變量所在緩存行的數(shù)據(jù)寫回到系統(tǒng)內(nèi)存。但是,就算寫回到內(nèi)存,如果其他處理器緩存的值還是舊的,再執(zhí)行計(jì)算操作就會(huì)有問題。所以,在多處理器下,為了保證各個(gè)處理器的緩存是一致的,就會(huì)實(shí)現(xiàn)緩存一致性協(xié)議,每個(gè)處理器通過嗅探在總線上傳播的數(shù)據(jù)來檢查自己緩存的值是不是過期了,當(dāng)處理器發(fā)現(xiàn)自己緩存行對(duì)應(yīng)的內(nèi)存地址被修改,就會(huì)將當(dāng)前處理器的緩行設(shè)置成無效狀態(tài),當(dāng)處理器對(duì)這個(gè)數(shù)據(jù)進(jìn)行修改操作的時(shí)候,會(huì)重新從系統(tǒng)內(nèi)存中把數(shù)據(jù)讀到處理器緩存里。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容