理解Java中volatile的語義

Java中的volatile變量大體上有3條語義,其中2條是針對volatile變量自身而言,另外1條說的是volatile變量對其它變量可見性的影響。

首先我們來看volatile自身的語義:

1,讀volatile變量總是可以讀到任何線程最近一次對該變量的寫入。這意味著java編譯器不會優(yōu)化volatile變量的讀寫,每次對volatile變量的寫入都會寫入主內(nèi)存,每次讀取volatile變量也都會從主內(nèi)存中讀取而不會把該變量暫存在工作內(nèi)存(寄存器)中。這就可以保證如下代碼可以工作:

private volatile boolean flag = false;

//線程1一直執(zhí)行如下循環(huán)等待flag變?yōu)閠rue:

while (flag == false) {

? ? ? ? doSomething();

}

//線程2在某個時刻執(zhí)行執(zhí)行:

flag = true;

也就是說線程2在某時刻設(shè)置flag的值為true后,線程1可以立即感知到。如果flag變量沒有volatile修飾,則線程1在線程2設(shè)置flag為true后不一定能夠感知到,這樣可能導(dǎo)致線程1永遠(yuǎn)跳不出那個循環(huán)。

2,對volatile變量的單個讀或單個寫操作都是原子操作。假如有如下代碼在兩個線程中同時執(zhí)行:

private volatile long count;

//線程1

count = 0x1234567890abcdef;

//線程2

count = 0x1111111122222222;

由于這兩個線程中執(zhí)行的都是單個寫操作,本條語義保證了其原子性,所以count最后的值只可能是0x1234567890abcdef或0x1111111122222222這兩者之一,不可能出現(xiàn)諸如0x1234567822222222這樣的非法值(如果count變量沒有volatile修飾的話,則可能出現(xiàn)這種非法值)。同理,如果不保證讀操作是原子性的,則讀的時候可能讀到非法值,即剛好讀了4個字節(jié),然后中間插入了對該變量的寫入,然后再讀剩下的4個字節(jié)。

重要:這條語義只是說明單個讀單個寫是原子的,并不保證又讀又寫這種復(fù)合操作是原子的。比如 它并不會保證couter++是原子的,因為counter++需要2次訪問內(nèi)存,即首先從內(nèi)存中讀取該值,然后加1,然后把結(jié)果寫入內(nèi)存。所以即使是存在volatile修飾的counter變量我們也不能在多個線程中沒有同步手段的保護(hù)下并發(fā)執(zhí)行counter++。

下面來看volatile變量對其它變量可見性的影響:

3,其它線程在觀察到線程A對volatile變量v的修改之時(后),也一定能夠觀察到線程A對源代碼中位于變量v之前的其它變量的修改。文字表達(dá)可能有點抽象,看下面的代碼:

int a, b;

volatile int c;

//線程1執(zhí)行:

a = 1;

b = 2;

c = 3;


//線程2執(zhí)行

if (c == 3) {

? ? ? ? //使用a和b

}

這段代碼可以保證線程2的if條件為真時,也就是當(dāng)c等于3時,a一定等于1, b一定等2。如果c不是volatile變量,則上述結(jié)論是不一定成立的。

從編程的角度來說,理解上面這幾條語義之后就可以寫出正確使用volatile變量的代碼了。

版權(quán)聲明:本文為原創(chuàng)文章,如需轉(zhuǎn)載,請注明出處。

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

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

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