編譯器和處理器必須同時(shí)遵守重排規(guī)則炬藤。多核處理器需使用內(nèi)存屏障指令來(lái)確保一致性虽界。即使編譯器優(yōu)化掉了一個(gè)字段訪問(wèn)(因?yàn)橐粋€(gè)讀入的值未被使用)摄乒,需要產(chǎn)生內(nèi)存屏障歹袁,就像這個(gè)訪問(wèn)仍然需要保護(hù)枷餐。(可參考下面的優(yōu)化掉內(nèi)存屏障的章節(jié))靶瘸。
內(nèi)存屏障指令僅直接控制CPU與其緩存之間,與垃圾回收機(jī)制中“寫(xiě)屏障(write barriers)”無(wú)關(guān)毛肋。
一怨咪、重排序
編譯器或者CPU的代碼的結(jié)構(gòu)重排排序,達(dá)到最佳效果润匙。
(1)編譯器重排
CPU只讀一次的x和y值诗眨。不需反復(fù)讀取寄存器來(lái)交替x和y值。
(2)處理器重排
寫(xiě)緩存區(qū)沒(méi)有及時(shí)刷新孕讳,使得處理器執(zhí)行的讀寫(xiě)操作與內(nèi)存上順序不一致匠楚。
處理器A讀b=0,處理器B讀a=0厂财。A1寫(xiě)a=1先寫(xiě)到處理器A的寫(xiě)緩存區(qū)中芋簿,此時(shí)內(nèi)存中a=0。如果這時(shí)處理器B從內(nèi)存中讀a璃饱,讀到的將是0与斤。
可能會(huì)出現(xiàn)x,y都是0。
二、內(nèi)存屏障
為了解決上述問(wèn)題撩穿,處理器提供內(nèi)存屏障指令(Memory Barrier):
寫(xiě)內(nèi)存屏障(Store Memory Barrier):處理器將存儲(chǔ)緩存值寫(xiě)回主存(阻塞方式)磷支。
讀內(nèi)存屏障(Load Memory Barrier):處理器,處理失效隊(duì)列(阻塞方式)食寡。
保證兩個(gè)操作之間數(shù)據(jù)的可見(jiàn)性雾狈。
volatile讀前插讀屏障,寫(xiě)后加寫(xiě)屏障冻河,避免CPU重排導(dǎo)致的問(wèn)題箍邮,實(shí)現(xiàn)多線程之間數(shù)據(jù)的可見(jiàn)性。
三叨叙、內(nèi)存屏障的種類(lèi)
StoreLoad開(kāi)銷(xiāo)最大锭弊。萬(wàn)能屏障,兼具其它三種內(nèi)存屏障功能擂错。執(zhí)行時(shí)味滞,處理器通常要把寫(xiě)緩沖區(qū)中的數(shù)據(jù)全部刷新的內(nèi)存中
對(duì)于處理器來(lái)說(shuō),內(nèi)存屏障會(huì)導(dǎo)致cpu緩存的刷新钮呀,刷新時(shí)剑鞍,會(huì)遵循緩存一致性協(xié)議。
lock:解鎖時(shí)爽醋,jvm會(huì)強(qiáng)制刷新cpu緩存蚁署,導(dǎo)致當(dāng)前線程更改,對(duì)其他線程可見(jiàn)蚂四。
volatile:標(biāo)記volatile的字段光戈,在寫(xiě)操作時(shí),會(huì)強(qiáng)制刷新cpu緩存遂赠,標(biāo)記volatile的字段久妆,每次讀取都是直接讀內(nèi)存。
final:即時(shí)編譯器在final寫(xiě)操作后跷睦,會(huì)插入內(nèi)存屏障筷弦,來(lái)禁止重排序,保證可見(jiàn)性