Java volatile 理解

1. 現(xiàn)代CPU Cache結(jié)構(gòu)

多核 CPU Cache 結(jié)構(gòu)
1.1 緩存的主要作用

現(xiàn)代多核CPU為了提升處理速度,都會(huì)將需要的數(shù)據(jù)從內(nèi)存拷貝到各自的緩存中(L1,L2),然后在各自的緩存中對(duì)數(shù)據(jù)進(jìn)行操作。

1.2 緩存的作用范圍

L1,L2 是CPU中每個(gè)核私有的,用于備份各自所需要的數(shù)據(jù)。L3 Cache是CPU每個(gè)核共享的。

1.3 緩存的寫入模式

寫回(write-back)模式:各個(gè)核每次修改自己緩存中的數(shù)據(jù)后不會(huì)立即寫回到內(nèi)存,而是等到一定合適的時(shí)間才寫回到內(nèi)存。
直寫(write-through)模式:各個(gè)核每次修改自己緩存中的數(shù)據(jù)后會(huì)立即寫回到內(nèi)存。

1.4 緩存的一致性

無論哪種寫入模式,試想,如果多個(gè)核都從內(nèi)存緩存了一份相同的數(shù)據(jù),而此時(shí)有一個(gè)核將自己緩存中的數(shù)據(jù)進(jìn)行了修改,其他核緩存中的數(shù)據(jù)卻依然是修改之前的數(shù)據(jù),這就造成了各個(gè)核之間緩存數(shù)據(jù)的不一致,而我們所期望的是各個(gè)核緩存之間的數(shù)據(jù)可以同步,為了達(dá)到同步的目的,各個(gè)核的緩存需要共同遵守一份協(xié)議,保證修改共享數(shù)據(jù)的時(shí)候可以通知其他緩存,這就是CPU的緩存一致性協(xié)議。

緩存一致性協(xié)議有多種,但是基本上都是基于MESI協(xié)議進(jìn)行擴(kuò)展的,詳細(xì)的內(nèi)容可以查閱相關(guān)文檔了解。

2. volatile的實(shí)現(xiàn)原理

2.1 可見性

可見性,即一個(gè)線程修改一個(gè)共享變量時(shí),其他線程可以獲取到修改后的值。JVM的實(shí)現(xiàn)中,volatile共享變量的寫操作會(huì)向處理器發(fā)送一條Lock指令,聲言使用直寫模式,在CPU緩存一致性協(xié)議的保證下實(shí)現(xiàn)volitile共享變量的可見性。

簡單來講,多核環(huán)境下,對(duì)volatile共享變量進(jìn)行寫操作會(huì)將緩存的結(jié)果直接寫回到內(nèi)存中,在緩存一致性協(xié)議下,其他核會(huì)對(duì)總線上傳輸?shù)臄?shù)據(jù)一直進(jìn)行窺探,即監(jiān)測(cè)其他核對(duì)緩存數(shù)據(jù)的操作。因此,volatile共享變量寫回內(nèi)存的操作會(huì)被其他核監(jiān)測(cè)到,此時(shí)這些核會(huì)將自己緩存中的數(shù)據(jù)設(shè)為無效狀態(tài),當(dāng)需要對(duì)這個(gè)數(shù)據(jù)進(jìn)行修改操作的時(shí)候會(huì)重新從內(nèi)存中讀取,這樣就達(dá)到了volatile修飾變量的可見性。

2.1 原子性

volatile修飾的變量無論是讀還是寫操作,都是具備原子性的,可以理解為使用了鎖:

volatile int value = 1;
public void set(int value) {
   this.value = value;
}
public void get() {
   return this.value;
}
int value = 1;
public synchronized void set(int value) {
   this.value = value;
}
public synchronized int get() {
   return this.value;
}

這意味著多線程環(huán)境下任何一個(gè)線程讀取到的volatile修飾的共享變量都是當(dāng)前的最新值,不會(huì)存在差異性。
但是有一點(diǎn)需要注意,volatile只是保證了讀/寫的原子性,復(fù)合的volatile操作并不保證原子性,例如:

volatile int value = 1
public void set(int value) {
   this.value = value++;
}

因?yàn)関alue++這個(gè)操作可以分為三個(gè)步驟,首先,讀取value的值,其次,
進(jìn)行自增操作,最后,將結(jié)果寫入內(nèi)存。需要知道這三個(gè)操作volatile并不能保證原子性,即只能保證讀取到的value是最新值,如果此時(shí)該處理器讀取value之后由于某些原因阻塞,而此時(shí)其他處理器剛好對(duì)value進(jìn)行了修改,這個(gè)時(shí)候之前的處理器進(jìn)行計(jì)算時(shí)還是使用之前讀取到的value,這樣就造成了錯(cuò)誤的處理結(jié)果。

最后編輯于
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,793評(píng)論 11 349
  • 擦肩而過,沒有遇上博子的藤井,回家看到信,匆匆寫了一封回信,講述了自己曾有一個(gè)高中時(shí)代的同班男生,和她同名同姓。博...
    魚耗子閱讀 237評(píng)論 0 0
  • 前言 好了,一個(gè)大齡老男人的悲情回憶環(huán)節(jié)結(jié)束,下面開始正題。 個(gè)人認(rèn)為想要在安卓開發(fā)的道路上走的很長遠(yuǎn),J2SE的...
    尼古拉斯_富貴閱讀 148評(píng)論 0 0

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