摘要:禁止指令重排序優(yōu)化。只有當(dāng)線(xiàn)程對(duì)變量執(zhí)行的前一個(gè)動(dòng)作是時(shí),才能對(duì)執(zhí)行動(dòng)作并且,只有當(dāng)對(duì)變量執(zhí)行的后一個(gè)動(dòng)作是時(shí),線(xiàn)程才能對(duì)變量執(zhí)行動(dòng)作。變量不需要與其他的狀態(tài)變量共同參與不變約束。在某些情況下,的同步機(jī)制性要優(yōu)于鎖。
當(dāng)一個(gè)變量定義為volatile之后,它具備兩種特性:
保證此變量對(duì)所有線(xiàn)程的可見(jiàn)性,這里的“可見(jiàn)性”是指當(dāng)一條線(xiàn)程修改了這個(gè)變量的值,新值對(duì)于其他線(xiàn)程來(lái)說(shuō)是可以立即得知的。
禁止指令重排序優(yōu)化。
在X86處理器下通過(guò)工具獲取 JIT編譯器生成的匯編指令來(lái)看下volatile變量進(jìn)行讀寫(xiě)操作時(shí)CPU的行為:
Java 代碼如下:
// volatile Object instance; instance = new Singleton();
生成的匯編代碼如下:
0x01a3de1d: movb $0X0, 0X1104800(%esi); 0X01a3de24: lock addl $0X0, (%esp);
有volatile變量修飾的共享變量進(jìn)行寫(xiě)操作的時(shí)候會(huì)多出第二行匯編代碼,Lock前綴的指令在多核處理器下會(huì)引發(fā)了兩件事件。
將當(dāng)前處理器緩存的數(shù)據(jù)寫(xiě)回到系統(tǒng)內(nèi)存。
這個(gè)寫(xiě)回內(nèi)存的操作會(huì)使在其他CPU里緩存了該內(nèi)存地址的數(shù)據(jù)無(wú)效。
再讓我們從Java內(nèi)存模型的角度分析下volatile變量。假定T表示一個(gè)線(xiàn)程,V和W分別表示兩個(gè)volatile變量,那么在進(jìn)行read, load, use, assign, store和write時(shí)需要滿(mǎn)足以下三條規(guī)則:
只有當(dāng)線(xiàn)程T對(duì)變量V執(zhí)行的前一個(gè)動(dòng)作是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。T對(duì)V的use動(dòng)作可以認(rèn)為是和線(xiàn)程T對(duì)V的load,read動(dòng)作相關(guān)聯(lián),必須連續(xù)一起出現(xiàn)(這條規(guī)則要求 在工作內(nèi)存中,每次使用V前都必須先從主內(nèi)存刷新最新的值,用于保證能看見(jiàn)其他線(xiàn)程對(duì)變量V所做的修改后的值)。
只有當(dāng)線(xiàn)程T對(duì)變量V執(zhí)行的前一個(gè)動(dòng)作是assign時(shí),T才能對(duì)V執(zhí)行store動(dòng)作;并且,只有當(dāng)T對(duì)變量V執(zhí)行的后一個(gè)動(dòng)作是store時(shí),線(xiàn)程T才能對(duì)變量V執(zhí)行assign動(dòng)作。線(xiàn)程T對(duì)變量V的assign動(dòng)作可認(rèn)為是和線(xiàn)程T對(duì)變量V的store, write動(dòng)作相關(guān)聯(lián),必須連續(xù)一起出現(xiàn)(這條規(guī)則要求 在工作內(nèi)存中,每次修改V后都必須立刻同步回主內(nèi)存中,用于保證其他線(xiàn)程可以看到自己對(duì)變量V所做的修改)。
假定動(dòng)作A是線(xiàn)程T對(duì)變量V實(shí)施的use或assign操作,假定動(dòng)作F是和動(dòng)作A相關(guān)聯(lián)的load或store動(dòng)作,假定動(dòng)作P是和動(dòng)作F相應(yīng)的變量V的read或write動(dòng)作;類(lèi)似的,假定動(dòng)作B是線(xiàn)程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)的變量W的read或write動(dòng)作。如果A先于B,那P先于Q(這條規(guī)則要求 volatile修飾的變量不會(huì)被指令重排序優(yōu)化,保證代碼的執(zhí)行順序與程序的順序相同)。
由于volatile變量只能保證可見(jiàn)性,在不符合以下兩條規(guī)則的運(yùn)算場(chǎng)景中,仍然要通過(guò)加鎖(使用synchronized或java.util.concurrent中的原子類(lèi))來(lái)保證原子性:
運(yùn)行結(jié)果并不依賴(lài)變量的當(dāng)前值,或者能夠確保只有單一的線(xiàn)程修改變量的值。
變量不需要與其他的狀態(tài)變量共同參與不變約束。
在某些情況下,volatile的同步機(jī)制性要優(yōu)于鎖。并且,volatile變量讀操作的性能消耗與普通變量幾乎沒(méi)有什么差別,但是寫(xiě)操作則可能會(huì)慢一些,因?yàn)樗枰诒镜卮a中插入許多內(nèi)存屏障指令來(lái)保證處理器不發(fā)生亂序執(zhí)行。
參考:
深入分析Volatile的實(shí)現(xiàn)原理
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/66049.html
摘要:內(nèi)存模型是圍繞著在并發(fā)過(guò)程中如何處理原子性可見(jiàn)性和有序性這個(gè)特征來(lái)建立的,我們來(lái)看下哪些操作實(shí)現(xiàn)了這個(gè)特性。可見(jiàn)性可見(jiàn)性是指當(dāng)一個(gè)線(xiàn)程修改了共享變量的值,其他線(xiàn)程能夠立即得知這個(gè)修改。 Java內(nèi)存模型是圍繞著在并發(fā)過(guò)程中如何處理原子性、可見(jiàn)性和有序性這3個(gè)特征來(lái)建立的,我們來(lái)看下哪些操作實(shí)現(xiàn)了這3個(gè)特性。 原子性(atomicity): 由Java內(nèi)存模型來(lái)直接保證原子性變量操作包括...
摘要:并發(fā)需要解決的問(wèn)題功能性問(wèn)題線(xiàn)程同步面臨兩個(gè)問(wèn)題,想象下有兩個(gè)線(xiàn)程在協(xié)作工作完成某項(xiàng)任務(wù)。鎖可用于規(guī)定一個(gè)臨界區(qū),同一時(shí)間臨界區(qū)內(nèi)僅能由一個(gè)線(xiàn)程訪問(wèn)。并發(fā)的數(shù)據(jù)結(jié)構(gòu)線(xiàn)程安全的容器,如等。 并發(fā)指在宏觀上的同一時(shí)間內(nèi)同時(shí)執(zhí)行多個(gè)任務(wù)。為了滿(mǎn)足這一需求,現(xiàn)代的操作系統(tǒng)都抽象出 線(xiàn)程 的概念,供上層應(yīng)用使用。 這篇博文不打算詳細(xì)展開(kāi)分析,而是對(duì)java并發(fā)中的概念和工具做一個(gè)梳理。沿著并發(fā)模...
摘要:我的是忙碌的一年,從年初備戰(zhàn)實(shí)習(xí)春招,年三十都在死磕源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實(shí)習(xí)。因?yàn)槲倚睦砗芮宄业哪繕?biāo)是阿里。所以在收到阿里之后的那晚,我重新規(guī)劃了接下來(lái)的學(xué)習(xí)計(jì)劃,將我的短期目標(biāo)更新成拿下阿里轉(zhuǎn)正。 我的2017是忙碌的一年,從年初備戰(zhàn)實(shí)習(xí)春招,年三十都在死磕JDK源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實(shí)習(xí)offer。然后五月懷著忐忑的心情開(kāi)始了螞蟻金...
摘要:三關(guān)鍵字能保證原子性嗎并發(fā)編程藝術(shù)這本書(shū)上說(shuō)保證但是在自增操作非原子操作上不保證,多線(xiàn)程編程核心藝術(shù)這本書(shū)說(shuō)不保證。多線(xiàn)程訪問(wèn)關(guān)鍵字不會(huì)發(fā)生阻塞,而關(guān)鍵字可能會(huì)發(fā)生阻塞關(guān)鍵字能保證數(shù)據(jù)的可見(jiàn)性,但不能保證數(shù)據(jù)的原子性。 系列文章傳送門(mén): Java多線(xiàn)程學(xué)習(xí)(一)Java多線(xiàn)程入門(mén) Java多線(xiàn)程學(xué)習(xí)(二)synchronized關(guān)鍵字(1) java多線(xiàn)程學(xué)習(xí)(二)synchroniz...
摘要:并發(fā)編程的挑戰(zhàn)并發(fā)編程的目的是為了讓程序運(yùn)行的更快,但是,并不是啟動(dòng)更多的線(xiàn)程就能讓程序最大限度的并發(fā)執(zhí)行。的實(shí)現(xiàn)原理與應(yīng)用在多線(xiàn)程并發(fā)編程中一直是元老級(jí)角色,很多人都會(huì)稱(chēng)呼它為重量級(jí)鎖。 并發(fā)編程的挑戰(zhàn) 并發(fā)編程的目的是為了讓程序運(yùn)行的更快,但是,并不是啟動(dòng)更多的線(xiàn)程就能讓程序最大限度的并發(fā)執(zhí)行。如果希望通過(guò)多線(xiàn)程執(zhí)行任務(wù)讓程序運(yùn)行的更快,會(huì)面臨非常多的挑戰(zhàn):(1)上下文切換(2)死...
閱讀 2912·2021-10-19 10:09
閱讀 3131·2021-10-09 09:41
閱讀 3378·2021-09-26 09:47
閱讀 2692·2019-08-30 15:56
閱讀 597·2019-08-29 17:04
閱讀 984·2019-08-26 11:58
閱讀 2509·2019-08-26 11:51
閱讀 3360·2019-08-26 11:29