并發(fā)關(guān)鍵字volatile(重排序和內(nèi)存屏障)

Java 語(yǔ)言中的volatile變量可以被看作是一種 “程度較輕的 synchronized”;synchronized 塊相比,volatile 變量所需的編碼較少,并且運(yùn)行時(shí)開(kāi)銷(xiāo)也較少,但是它所能實(shí)現(xiàn)的功能也僅是 synchronized 的一部分。

鎖和volatile

鎖提供了兩種主要特性:原子性和可見(jiàn)性与斤。

原子性即一次只允許一個(gè)線(xiàn)程持有某個(gè)特定的鎖,一次就只有一個(gè)線(xiàn)程能夠使用共享數(shù)據(jù)荚恶×么可見(jiàn)性是必須確保釋放鎖之前對(duì)共享數(shù)據(jù)做出的更改對(duì)于隨后獲得該鎖的另一個(gè)線(xiàn)程是可見(jiàn)的 。

Volatile 變量具有 synchronized 的可見(jiàn)性特性谒撼,但是不具備原子特性食寡。
當(dāng)一個(gè)變量定義為 volatile 之后,將具備:

1.保證此變量對(duì)所有的線(xiàn)程的可見(jiàn)性廓潜,當(dāng)一個(gè)線(xiàn)程修改了這個(gè)變量的值抵皱,volatile 保證了新值能立即同步到主內(nèi)存,其它線(xiàn)程每次使用前立即從主內(nèi)存刷新辩蛋。但普通變量做不到這點(diǎn)呻畸,普通變量的值在線(xiàn)程間傳遞均需要通過(guò)主內(nèi)存來(lái)完成。
2.禁止指令重排序優(yōu)化悼院。有volatile修飾的變量伤为,賦值后多執(zhí)行了一個(gè)“l(fā)oad addl $0x0, (%esp)”操作,這個(gè)操作相當(dāng)于一個(gè)內(nèi)存屏障(指令重排序時(shí)不能把后面的指令重排序到內(nèi)存屏障之前的位置)据途。

我們通過(guò)有序性來(lái)詳細(xì)看下指令重排序绞愚。

指令重排序

有序性:即程序執(zhí)行的順序按照代碼的先后順序執(zhí)行叙甸。舉個(gè)簡(jiǎn)單的例子,看下面這段代碼:

int i = 0;              
boolean flag = false;
i = 1;                //語(yǔ)句1  
flag = true;          //語(yǔ)句2

從代碼順序上看位衩,語(yǔ)句1是在語(yǔ)句2前面的裆蒸,那么JVM在真正執(zhí)行這段代碼的時(shí)候會(huì)保證語(yǔ)句1一定會(huì)在語(yǔ)句2前面執(zhí)行嗎?不一定蚂四,為什么呢光戈?這里可能會(huì)發(fā)生指令重排序(Instruction Reorder)。
指令重排序:

一般來(lái)說(shuō)遂赠,處理器為了提高程序運(yùn)行效率,可能會(huì)對(duì)輸入代碼進(jìn)行優(yōu)化晌杰,它不保證程序中各個(gè)語(yǔ)句的執(zhí)行先后順序同代碼中的順序一致跷睦,但是它會(huì)保證程序最終執(zhí)行結(jié)果和代碼順序執(zhí)行的結(jié)果是一致的。

比如上面的代碼中肋演,語(yǔ)句1和語(yǔ)句2誰(shuí)先執(zhí)行對(duì)最終的程序結(jié)果并沒(méi)有影響抑诸,那么就有可能在執(zhí)行過(guò)程中,語(yǔ)句2先執(zhí)行而語(yǔ)句1后執(zhí)行爹殊。雖然處理器會(huì)對(duì)指令進(jìn)行重排序蜕乡,但是它會(huì)保證程序最終結(jié)果會(huì)和代碼順序執(zhí)行結(jié)果相同,那么它靠什么保證的呢梗夸?靠的是數(shù)據(jù)依賴(lài)性:

編譯器和處理器在重排序時(shí)层玲,會(huì)遵守?cái)?shù)據(jù)依賴(lài)性,編譯器和處理器不會(huì)改變存在數(shù)據(jù)依賴(lài)關(guān)系的兩個(gè)操作的執(zhí)行順序反症。

舉例如下代碼

double pi  = 3.14;    //A  
double r   = 1.0;     //B  
double area = pi * r * r; //C  

上面三個(gè)操作的數(shù)據(jù)依賴(lài)關(guān)系如下圖所示

20151008235938677.png

A和C之間存在數(shù)據(jù)依賴(lài)關(guān)系辛块,同時(shí)B和C之間也存在數(shù)據(jù)依賴(lài)關(guān)系。因此在最終執(zhí)行的指令序列中铅碍,C不能被重排序到A和B的前面(C排到A和B的前面润绵,程序的結(jié)果將會(huì)被改變)。但A和B之間沒(méi)有數(shù)據(jù)依賴(lài)關(guān)系胞谈,編譯器和處理器可以重排序A和B之間的執(zhí)行順序尘盼。下圖是該程序的兩種執(zhí)行順序:


20151009000030517.png

在計(jì)算機(jī)中,軟件技術(shù)和硬件技術(shù)有一個(gè)共同的目標(biāo):在不改變程序執(zhí)行結(jié)果的前提下烦绳,盡可能的開(kāi)發(fā)并行度卿捎。編譯器和處理器都遵從這一目標(biāo)。
這里所說(shuō)的數(shù)據(jù)依賴(lài)性?xún)H針對(duì)單個(gè)處理器中執(zhí)行的指令序列和單個(gè)線(xiàn)程中執(zhí)行的操作爵嗅,在單線(xiàn)程程序中娇澎,對(duì)存在控制依賴(lài)的操作重排序,不會(huì)改變執(zhí)行結(jié)果睹晒;但在多線(xiàn)程程序中趟庄,對(duì)存在控制依賴(lài)的操作重排序括细,可能會(huì)改變程序的執(zhí)行結(jié)果。這是就需要內(nèi)存屏障來(lái)保證可見(jiàn)性了戚啥。

內(nèi)存屏障

內(nèi)存屏障分為兩種:Load Barrier 和 Store Barrier即讀屏障和寫(xiě)屏障奋单。
內(nèi)存屏障有兩個(gè)作用:

1.阻止屏障兩側(cè)的指令重排序;
2.強(qiáng)制把寫(xiě)緩沖區(qū)/高速緩存中的臟數(shù)據(jù)等寫(xiě)回主內(nèi)存猫十,讓緩存中相應(yīng)的數(shù)據(jù)失效览濒。

  • 對(duì)于Load Barrier來(lái)說(shuō),在指令前插入Load Barrier拖云,可以讓高速緩存中的數(shù)據(jù)失效贷笛,強(qiáng)制從新從主內(nèi)存加載數(shù)據(jù);
  • 對(duì)于Store Barrier來(lái)說(shuō)宙项,在指令后插入Store Barrier乏苦,能讓寫(xiě)入緩存中的最新數(shù)據(jù)更新寫(xiě)入主內(nèi)存,讓其他線(xiàn)程可見(jiàn)尤筐。

java的內(nèi)存屏障通常所謂的四種即LoadLoad,StoreStore,LoadStore,StoreLoad實(shí)際上也是上述兩種的組合汇荐,完成一系列的屏障和數(shù)據(jù)同步功能。

LoadLoad屏障:對(duì)于這樣的語(yǔ)句Load1; LoadLoad; Load2盆繁,在Load2及后續(xù)讀取操作要讀取的數(shù)據(jù)被訪問(wèn)前掀淘,保證Load1要讀取的數(shù)據(jù)被讀取完畢。
StoreStore屏障:對(duì)于這樣的語(yǔ)句Store1; StoreStore; Store2油昂,在Store2及后續(xù)寫(xiě)入操作執(zhí)行前革娄,保證Store1的寫(xiě)入操作對(duì)其它處理器可見(jiàn)。
LoadStore屏障:對(duì)于這樣的語(yǔ)句Load1; LoadStore; Store2秕狰,在Store2及后續(xù)寫(xiě)入操作被刷出前稠腊,保證Load1要讀取的數(shù)據(jù)被讀取完畢。
StoreLoad屏障:對(duì)于這樣的語(yǔ)句Store1; StoreLoad; Load2鸣哀,在Load2及后續(xù)所有讀取操作執(zhí)行前架忌,保證Store1的寫(xiě)入對(duì)所有處理器可見(jiàn)。它的開(kāi)銷(xiāo)是四種屏障中最大的我衬。在大多數(shù)處理器的實(shí)現(xiàn)中叹放,這個(gè)屏障是個(gè)萬(wàn)能屏障,兼具其它三種內(nèi)存屏障的功能

volatile的內(nèi)存屏障策略非常嚴(yán)格保守挠羔,非常悲觀且毫無(wú)安全感的心態(tài):

在每個(gè)volatile寫(xiě)操作前插入StoreStore屏障井仰,在寫(xiě)操作后插入StoreLoad屏障;
在每個(gè)volatile讀操作前插入LoadLoad屏障破加,在讀操作后插入LoadStore屏障俱恶;

由于內(nèi)存屏障的作用,避免了volatile變量和其它指令重排序、線(xiàn)程之間實(shí)現(xiàn)了通信合是,使得volatile表現(xiàn)出了鎖的特性了罪。

volatile 性能:

volatile 的讀性能消耗與普通變量幾乎相同,但是寫(xiě)操作稍慢聪全,因?yàn)樗枰诒镜卮a中插入許多內(nèi)存屏障指令來(lái)保證處理器不發(fā)生亂序執(zhí)行泊藕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市难礼,隨后出現(xiàn)的幾起案子娃圆,更是在濱河造成了極大的恐慌,老刑警劉巖蛾茉,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讼呢,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡谦炬,警方通過(guò)查閱死者的電腦和手機(jī)吝岭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吧寺,“玉大人,你說(shuō)我怎么就攤上這事散劫≈苫” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵获搏,是天一觀的道長(zhǎng)赖条。 經(jīng)常有香客問(wèn)我,道長(zhǎng)常熙,這世上最難降的妖魔是什么纬乍? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮裸卫,結(jié)果婚禮上仿贬,老公的妹妹穿的比我還像新娘。我一直安慰自己墓贿,他們只是感情好茧泪,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著聋袋,像睡著了一般队伟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上幽勒,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天嗜侮,我揣著相機(jī)與錄音,去河邊找鬼。 笑死锈颗,一個(gè)胖子當(dāng)著我的面吹牛顷霹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播宜猜,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼泼返,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了姨拥?” 一聲冷哼從身側(cè)響起绅喉,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎叫乌,沒(méi)想到半個(gè)月后柴罐,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡憨奸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年革屠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片排宰。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡似芝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出板甘,到底是詐尸還是另有隱情党瓮,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布盐类,位于F島的核電站寞奸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏在跳。R本人自食惡果不足惜枪萄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望猫妙。 院中可真熱鬧瓷翻,春花似錦、人聲如沸吐咳。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)韭脊。三九已至童谒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沪羔,已是汗流浹背饥伊。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工象浑, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人琅豆。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓愉豺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親茫因。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蚪拦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

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