volatile變量

? ? ? ? 上篇文章介紹了Java內(nèi)存模型抚芦,沒(méi)看過(guò)《深入理解Java虛擬機(jī)》的同學(xué)可以去看下Java內(nèi)存模型

? ? ? ? Java內(nèi)存模型對(duì)volatile專門(mén)定義了一些特殊的訪問(wèn)規(guī)則,假定T表示一個(gè)線程袖订,V和W分別表示兩個(gè)volatile變量勤揩,那么在進(jìn)行read旋奢、load润匙、use疫诽、assign、store鳍鸵、和write操作時(shí)需要滿足如下規(guī)則

1)只有當(dāng)線程T對(duì)變量V執(zhí)行的前一個(gè)動(dòng)作時(shí)load的時(shí)候苇瓣,線程T才能對(duì)變量V執(zhí)行use動(dòng)作。并且只有線程T對(duì)變量V執(zhí)行的后一個(gè)動(dòng)作是use的時(shí)候权纤,線程T才能對(duì)變量V執(zhí)行l(wèi)oad動(dòng)作钓简。線程T對(duì)變量V的use動(dòng)作可以認(rèn)為是和線程T對(duì)變量V的load、read動(dòng)作相關(guān)聯(lián)汹想,必須連續(xù)一起出現(xiàn)(這條規(guī)則要求在工作內(nèi)存中外邓,每次使用V前都必須先從主內(nèi)存刷新最新的值,用于保證能看見(jiàn)其他線程對(duì)變量V所做的修改后的值)

2)只有當(dāng)線程T對(duì)變量V執(zhí)行的前一個(gè)動(dòng)作時(shí)assign的時(shí)候古掏,線程T才能對(duì)變量V執(zhí)行store動(dòng)作损话,并且,只有當(dāng)線程T對(duì)變量V執(zhí)行的后一個(gè)動(dòng)作是store的時(shí)候槽唾,線程T才能對(duì)變量V執(zhí)行assign動(dòng)作丧枪。線程T對(duì)變量V的assign動(dòng)作可以認(rèn)為是和線程T對(duì)變量V的store、wtite動(dòng)作相關(guān)聯(lián)庞萍,必須連續(xù)一起出現(xiàn)(這條規(guī)則要求在工作內(nèi)存中拧烦,每次修改V后都必須立刻同步回主內(nèi)存中,用于保證其他線程可以看見(jiàn)自己對(duì)變量V所做的修改)

3)假定動(dòng)作A是線程T對(duì)變量V實(shí)施的use或assign動(dòng)作钝计,動(dòng)作F是和動(dòng)作A相關(guān)聯(lián)的load或store動(dòng)作恋博,假定動(dòng)作P是和動(dòng)作F相對(duì)應(yīng)的對(duì)變量V的read或write動(dòng)作;類似的私恬,假定動(dòng)作B是線程T對(duì)變量W實(shí)施的use或assign動(dòng)作债沮,假定動(dòng)作G是和動(dòng)作B相關(guān)聯(lián)的load或store動(dòng)作,假定動(dòng)作Q是和動(dòng)作G相應(yīng)的對(duì)變量W的read或write動(dòng)作本鸣。如果A先于B疫衩,那么P先于Q(這條規(guī)則要求volatile修改的變量不會(huì)被指令重排序優(yōu)化,保證代碼的執(zhí)行順序與程序的順序相同)

可以說(shuō)volatile關(guān)鍵字是Java虛擬機(jī)提供的最輕量級(jí)的同步機(jī)制荣德。

? ? ? ? 當(dāng)一個(gè)變量定義為volatile之后具備如下特性:

? ? ? ? 1.可見(jiàn)性:指當(dāng)一條線程修改了這個(gè)變量的值闷煤,新值對(duì)于其他線程來(lái)說(shuō)是可以立即得知的。普通變量的值在線程間傳遞均需通過(guò)主內(nèi)存來(lái)完成涮瞻,例:線程A修改了一個(gè)普通變量的值曹傀,然后向主內(nèi)存進(jìn)行回寫(xiě),另外一條線程B在線程A回寫(xiě)完成了后再?gòu)闹鲀?nèi)存進(jìn)行讀取操作饲宛,新變量的值才會(huì)對(duì)線程B可見(jiàn)。

? ? ? ? 雖然volatile型變量是線程可見(jiàn)的嗜价,對(duì)volatile變量所有的讀寫(xiě)都能立刻反應(yīng)到其他線程之中艇抠,但基于volatile變量的運(yùn)算在并發(fā)下并不是安全的幕庐,因?yàn)镴ava里面的運(yùn)算并不是原子操作。例:race ++家淤,我們用javap反編譯這句代碼會(huì)發(fā)現(xiàn)在Class文件中是由4條字節(jié)碼指令構(gòu)成异剥,(這里圖1是書(shū)中原圖,圖2是筆者自己反編譯的絮重,可能由于Java虛擬機(jī)版本的問(wèn)題2者不太一樣冤寿,請(qǐng)知道的大佬告知,為文章嚴(yán)謹(jǐn)性看圖1就可以了)

圖1
圖2

從字節(jié)碼層面很容易分析出來(lái)青伤,假如有兩條線程同時(shí)執(zhí)行這條語(yǔ)句督怜,線程A執(zhí)行g(shù)etstatic指令把race的值取到操作棧頂時(shí),volatile關(guān)鍵字保證來(lái)race的值在此時(shí)是正確的狠角,但是執(zhí)行iconst_1号杠、iadd這些指令時(shí)線程B可能已經(jīng)把race的值加大了,而在操作棧定的值就變成了過(guò)期的數(shù)據(jù)丰歌。

? ? ? ? 由于volatile變量只能保證可見(jiàn)性姨蟋,所以在不符合以下兩條規(guī)則的運(yùn)算場(chǎng)景中,我們?nèi)匀灰ㄟ^(guò)加鎖來(lái)保證原子性

? ? ? ? 1)運(yùn)算結(jié)果并不依賴變量的當(dāng)前值立帖,或者能夠確保只有單一的線程修改變量的值

? ? ? ? 2)變量不需要與其他的狀態(tài)變量共同參與不變約束

2.禁止指令重排序優(yōu)化眼溶,這里說(shuō)明下,為了使處理器內(nèi)部的運(yùn)算單元能盡量被充分利用晓勇,處理器可能會(huì)對(duì)輸入代碼進(jìn)行亂序執(zhí)行優(yōu)化堂飞。與之類似的Java虛擬機(jī)的即時(shí)編譯器也有指令重排序優(yōu)化。還不知道的同學(xué)可以去查下(說(shuō)的就是我自己)宵蕉。

? ? ? ? 普通的變量?jī)H僅會(huì)保證在該方法的執(zhí)行過(guò)程中所有依賴值結(jié)果的地方都能獲取到正確的結(jié)果酝静,而不能保證變量賦值操作的順序與程序代碼中的執(zhí)行順序一致。這樣理解起來(lái)還是有點(diǎn)抽象羡玛,筆者舉個(gè)自己在書(shū)中看了茅塞頓開(kāi)的例子

這里是一段匯編代碼别智,方便起見(jiàn)就用書(shū)中原圖了

這是段標(biāo)準(zhǔn)的DCL單例,變量用valatile修飾稼稿,賦值后(mov%eax薄榛,0x150(%esi)這句便是賦值操作)多執(zhí)行了一個(gè)“l(fā)ock addl & 0x0,(%esp)”操作让歼,這個(gè)操作相當(dāng)于一個(gè)內(nèi)存屏障敞恋,只有一個(gè)cpu訪問(wèn)時(shí)并不需要內(nèi)存屏障,但如果有兩個(gè)或更多cpu訪問(wèn)同一塊內(nèi)存谋右,且其中一個(gè)在觀測(cè)另一個(gè)硬猫,就需要內(nèi)存屏障來(lái)保證一致性了。這句指令“addl & 0x0,(%esp)”(把esp寄存器的值加0)顯然是一個(gè)空操作啸蜜,關(guān)鍵在于lock前綴坑雅,它的作用是使得本cpu的Cache寫(xiě)入了內(nèi)存,該寫(xiě)入動(dòng)作也會(huì)引起別的cpu或者別的內(nèi)核無(wú)效化其Cache衬横,這中操作箱單于對(duì)Cache中的變量做了一個(gè)“store和write”操作裹粤。所以通過(guò)這樣一個(gè)空操作可以讓前面valatile變量的修改對(duì)其他cpu立即可見(jiàn)。

? ? ? ? 這段基本是書(shū)中原文蜂林,這樣說(shuō)可能有的同學(xué)不太懂(我就沒(méi)懂)遥诉,下面在結(jié)合具體代碼說(shuō)下,instance = new Singleton() 這句代碼并不是一個(gè)原子操作噪叙,大致做了3件事情

1)給Singleton實(shí)例分配內(nèi)存空間

2)初始化Singleton對(duì)象

3)將instance對(duì)象指向分配的內(nèi)存空間

由于Java虛擬機(jī)指令重排序優(yōu)化矮锈,使得2、3的順序是無(wú)法保證的构眯,如果出現(xiàn)了132的情況愕难,并且在3執(zhí)行完畢2未執(zhí)行之前線程切換了,這個(gè)時(shí)候instance非空惫霸,所以直接返回instance猫缭,結(jié)果可想而知

? ? 避免篇幅過(guò)長(zhǎng)就到這吧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市壹店,隨后出現(xiàn)的幾起案子猜丹,更是在濱河造成了極大的恐慌,老刑警劉巖硅卢,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件射窒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡将塑,警方通過(guò)查閱死者的電腦和手機(jī)脉顿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)点寥,“玉大人艾疟,你說(shuō)我怎么就攤上這事「冶纾” “怎么了蔽莱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)戚长。 經(jīng)常有香客問(wèn)我盗冷,道長(zhǎng),這世上最難降的妖魔是什么同廉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任仪糖,我火速辦了婚禮柑司,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘乓诽。我一直安慰自己帜羊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布鸠天。 她就那樣靜靜地躺著,像睡著了一般帐姻。 火紅的嫁衣襯著肌膚如雪稠集。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天饥瓷,我揣著相機(jī)與錄音剥纷,去河邊找鬼。 笑死呢铆,一個(gè)胖子當(dāng)著我的面吹牛晦鞋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播棺克,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼悠垛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了娜谊?” 一聲冷哼從身側(cè)響起确买,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纱皆,沒(méi)想到半個(gè)月后湾趾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡派草,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年搀缠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片近迁。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡艺普,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出钳踊,到底是詐尸還是另有隱情衷敌,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布拓瞪,位于F島的核電站缴罗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏祭埂。R本人自食惡果不足惜面氓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一兵钮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧舌界,春花似錦掘譬、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至藐握,卻和暖如春靴拱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背猾普。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工袜炕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人初家。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓偎窘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親溜在。 傳聞我的和親對(duì)象是個(gè)殘疾皇子陌知,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 第6章類文件結(jié)構(gòu) 6.1 概述 6.2 無(wú)關(guān)性基石 6.3 Class類文件的結(jié)構(gòu) java虛擬機(jī)不和包括java...
    kennethan閱讀 910評(píng)論 0 2
  • 轉(zhuǎn)載自 IBM Java 理論與實(shí)踐: 正確使用 Volatile 變量 你真的了解volatile關(guān)鍵字嗎? v...
    LongHuang閱讀 1,323評(píng)論 1 4
  • 昨天去考試炕泳,在考場(chǎng)上遇到之前的老師纵诞,上了歲數(shù)一老頭一大早站在考場(chǎng)外,生怕學(xué)生臨時(shí)有什么問(wèn)題培遵,他可以回答他們的問(wèn)題浙芙。...
    許多的yolyol閱讀 180評(píng)論 1 1
  • 十七歲的某一天,那年盛夏籽腕,那年心動(dòng)嗡呼,某月相識(shí),某月回首皇耗,五日定情南窗,二十二日綿長(zhǎng),許你安好郎楼。放蕩不羈獨(dú)愛(ài)自由万伤,零碎不...
    淑媛媛閱讀 221評(píng)論 1 2