那就要重提volatile變量規(guī)則: 對一個volatile域的寫,happens-before于后續(xù)對這個volatile域的讀。 這條再拎出來說,其實就是如果一個變量聲明成是volatile的,那么當(dāng)我讀變量時,總是能讀到它的最新值,這里最新值是指不管其它哪個線程對該變量做了寫操作,都會立刻被更新到主存里,我也能從主存里讀到這個剛寫入的值。也就是說volatile關(guān)鍵字可以保證可見性以及有序性。
繼續(xù)拿上面的一段代碼舉例:
這段代碼不僅僅受到重排序的困擾,即使1、2沒有重排序。3也不會那么順利的執(zhí)行的。假設(shè)還是線程1先執(zhí)行write操作,線程2再執(zhí)行multiply操作,由于線程1是在工作內(nèi)存里把flag賦值為1,不一定立刻寫回主存,所以線程2執(zhí)行時,multiply再從主存讀flag值,仍然可能為false,那么括號里的語句將不會執(zhí)行。
如果改成下面這樣:

那么線程1先執(zhí)行write,線程2再執(zhí)行multiply。根據(jù)happens-before原則,這個過程會滿足以下3類規(guī)則:
程序順序規(guī)則:1 happens-before 2; 3 happens-before 4; (volatile限制了指令重排序,所以1 在2 之前執(zhí)行)
volatile規(guī)則:2 happens-before 3
傳遞性規(guī)則:1 happens-before 4
從內(nèi)存語義上來看
當(dāng)寫一個volatile變量時,JMM會把該線程對應(yīng)的本地內(nèi)存中的共享變量刷新到主內(nèi)存
當(dāng)讀一個volatile變量時,JMM會把該線程對應(yīng)的本地內(nèi)存置為無效,線程接下來將從主內(nèi)存中讀取共享變量。