關(guān)于volatile變量的內(nèi)存可見(jiàn)性,我在JVM群中拋出了一個(gè)問(wèn)題,然后我的一些認(rèn)知就被顛覆了。
問(wèn)題
請(qǐng)教一個(gè)問(wèn)題,a,b,c三個(gè)變量,其中c是volatile的,a,b是普通變量, a = 1, b = 2, c = 3, c寫(xiě)入之后,a,b的值也會(huì)被刷入緩存嗎,還是c寫(xiě)入之前所有在cpu緩存的數(shù)據(jù)都會(huì)被刷入內(nèi)存,還是只刷入和c在同一個(gè)緩存行的數(shù)據(jù)?
一開(kāi)始,我的認(rèn)知是后者,只刷入同一個(gè)緩存行的數(shù)據(jù)。
R大問(wèn)答
你們要按happens before來(lái)考慮這種問(wèn)題,不要整天無(wú)謂想著擦車(chē)(cache),Java的修正過(guò)的內(nèi)存模型其實(shí)基本點(diǎn)很簡(jiǎn)單,同一線(xiàn)程內(nèi)的副作用按程序順序發(fā)生,所以a、b、c的賦值如果是在同一線(xiàn)程內(nèi)按這個(gè)順序?qū)懙?,?shí)際執(zhí)行就要按照這個(gè)順序發(fā)生(至少表象上要按照這個(gè)順序;在程序無(wú)法感知順序差異時(shí)可以作弊)
這樣就是a賦值happens before b賦值,b賦值happens before c賦值,而不同線(xiàn)程之間的操作則是沒(méi)有happens before關(guān)系的,除非有volatile或者synchronized等帶有跨線(xiàn)程happen before關(guān)系的操作。不同線(xiàn)程之間的非volatile、非synchronized操作直接要想有傳遞的happens before關(guān)系的話(huà),中間就肯定得有能產(chǎn)生happens before關(guān)系的volatile或者synchronized操作。
什么寄存器啊、緩存啊啥的不必扯進(jìn)來(lái)。
我的反應(yīng)
哦~~~問(wèn)號(hào)臉。。。
R大繼續(xù)解釋
JVM實(shí)現(xiàn)的時(shí)候是要把這些概念映射下去的(這里的概念應(yīng)該就是happens before),但是當(dāng)你在思考高層程序語(yǔ)義的時(shí)候卻拿不合適的低層語(yǔ)義去解釋就很別扭,映射下去的辦法就是先有高層語(yǔ)義,然后看具體硬件上提供了哪些原語(yǔ),然后再去實(shí)現(xiàn)。例如說(shuō)在SPARC上它默認(rèn)是TSO(total store order)的,在上面需要手工做的同步操作就很簡(jiǎn)單。
曉銘大大的總結(jié)
JIT的時(shí)候會(huì)去查操作數(shù)的屬性,如果是volatile會(huì)在讀寫(xiě)操作附近生成barrier的中間表示,最終barrier中間表示會(huì)變成什么指令,那要根據(jù)具體的機(jī)器,Memory consistency是一個(gè)spec,各種硬件系統(tǒng)包括cache都是實(shí)現(xiàn)的細(xì)節(jié)。
總結(jié)
總結(jié)起來(lái),我這個(gè)問(wèn)題問(wèn)的不好,沒(méi)水準(zhǔn),問(wèn)題直接從jmm跳到了硬件具體實(shí)現(xiàn),中間還隔著一層硬件的memory model。
所以緩存到底怎么刷,不同的CPU、不同廠(chǎng)商、不同型號(hào)實(shí)現(xiàn)可能都不一樣,一個(gè)人想了解所有似乎是個(gè)不可能的任務(wù),也不實(shí)用,只需要搞清楚JMM層面的東西就OK,管它到底怎么刷。
推廣

知識(shí)星球可以干什么?
1、【分享】高質(zhì)量的技術(shù)文章
2、【沉淀】「戰(zhàn)狼群」高質(zhì)量問(wèn)題&解決方案
3、【成長(zhǎng)】項(xiàng)目經(jīng)驗(yàn),生活隨筆,學(xué)習(xí)心得
4、【復(fù)盤(pán)】實(shí)戰(zhàn)經(jīng)驗(yàn),故障總結(jié)
5、【面經(jīng)】面試經(jīng)驗(yàn)分享與總結(jié)
6、【推薦】技術(shù)書(shū)籍,崗位招聘