資源描述:
《深入java底層:內(nèi)存屏障與jvm并發(fā)詳解》由會(huì)員上傳分享,免費(fèi)在線(xiàn)閱讀,更多相關(guān)內(nèi)容在應(yīng)用文檔-天天文庫(kù)。
1、http://www.bjaccp.com深入Java底層:內(nèi)存屏障與JVM并發(fā)詳解內(nèi)存屏障,又稱(chēng)內(nèi)存柵欄,是一組處理器指令,用于實(shí)現(xiàn)對(duì)內(nèi)存操作的順序限制。本文假定讀者已經(jīng)充分掌握了相關(guān)概念和Java內(nèi)存模型,不討論并發(fā)互斥、并行機(jī)制和原子性。內(nèi)存屏障用來(lái)實(shí)現(xiàn)并發(fā)編程中稱(chēng)為可見(jiàn)性(visibility)的同樣重要的作用?! ?nèi)存屏障為何重要? 對(duì)主存的一次訪(fǎng)問(wèn)一般花費(fèi)硬件的數(shù)百次時(shí)鐘周期。處理器通過(guò)緩存(caching)能夠從數(shù)量級(jí)上降低內(nèi)存延遲的成本這些緩存為了性能重新排列待定內(nèi)存操作的順序。也就是說(shuō),程序的讀寫(xiě)操作不一定會(huì)按照它要求
2、處理器的順序執(zhí)行。當(dāng)數(shù)據(jù)是不可變的,同時(shí)/或者數(shù)據(jù)限制在線(xiàn)程范圍內(nèi),這些優(yōu)化是無(wú)害的?! ∪绻堰@些優(yōu)化與對(duì)稱(chēng)多處理(symmetricmulti-processing)和共享可變狀態(tài)(sharedmutablestate)結(jié)合,那么就是一場(chǎng)噩夢(mèng)。當(dāng)基于共享可變狀態(tài)的內(nèi)存操作被重新排序時(shí),程序可能行為不定。一個(gè)線(xiàn)程寫(xiě)入的數(shù)據(jù)可能被其他線(xiàn)程可見(jiàn),原因是數(shù)據(jù)寫(xiě)入的順序不一致。適當(dāng)?shù)姆胖脙?nèi)存屏障通過(guò)強(qiáng)制處理器順序執(zhí)行待定的內(nèi)存操作來(lái)避免這個(gè)問(wèn)題?! ?nèi)存屏障的協(xié)調(diào)作用 內(nèi)存屏障不直接由JVM暴露,相反它們被JVM插入到指令序列中以維持語(yǔ)言層并
3、發(fā)原語(yǔ)的語(yǔ)義。我們研究幾個(gè)簡(jiǎn)單Java程序的源代碼和匯編指令。首先快速看一下Dekker算法中的內(nèi)存屏障。該算法利用volatile變量協(xié)調(diào)兩個(gè)線(xiàn)程之間的共享資源訪(fǎng)問(wèn)。 請(qǐng)不要關(guān)注該算法的出色細(xì)節(jié)。哪些部分是相關(guān)的?每個(gè)線(xiàn)程通過(guò)發(fā)信號(hào)試圖進(jìn)入代碼第一行的關(guān)鍵區(qū)域。如果線(xiàn)程在第三行意識(shí)到?jīng)_突(兩個(gè)線(xiàn)程都要訪(fǎng)問(wèn)),通過(guò)turn變量的操作來(lái)解決。在任何時(shí)刻只有一個(gè)線(xiàn)程可以訪(fǎng)問(wèn)關(guān)鍵區(qū)域。 1.//coderunbyfirstthread????//coderunbysecondthread 2. 3.1???intentFirst=tru
4、e;?????????intentSecond=true; 4.2 5.3???while(intentSecond)??while(intentFirst)??????//volatileread 6.4????if(turn!=0){?????if(turn!=1){??????//volatileread 7.5??????intentFirst=false;???????intentSecond=false; 8.6??????while(turn!=0){}???????while(turn!=1){} 9.7???
5、???intentFirst=true;???????intentSecond=true; 10.8????}??????????????} 11.9 12.10???criticalSection();??criticalSection(); 13.11 14.12???turn=1;????turn=0;????????????????//volatilewrite 15.13???intentFirst=false;??intentSecond=false;????//volatilewrite 硬件優(yōu)化可以在沒(méi)有內(nèi)存
6、屏障的情況下打亂這段代碼,即使編譯器按照程序員的想法順序列出所有的內(nèi)存操作??紤]第三、四行的兩次順序volatile讀操作。每一個(gè)線(xiàn)程檢查其他線(xiàn)程是否發(fā)信號(hào)想進(jìn)入關(guān)鍵區(qū)域,然后檢查輪到誰(shuí)操作了。考慮第12、13行的兩次順序?qū)懖僮?。每一個(gè)線(xiàn)程把訪(fǎng)問(wèn)權(quán)釋放給其他線(xiàn)程,然后撤銷(xiāo)自己訪(fǎng)問(wèn)關(guān)鍵區(qū)域的意圖。讀線(xiàn)程應(yīng)該從不期望在其他線(xiàn)程撤銷(xiāo)訪(fǎng)問(wèn)意愿后觀察到其他線(xiàn)程對(duì)turn變量的寫(xiě)操作。這是個(gè)災(zāi)難。 但是如果這些變量沒(méi)有volatile修飾符,這的確會(huì)發(fā)生!例如,沒(méi)有volatile修飾符,第二個(gè)線(xiàn)程在第一個(gè)線(xiàn)程對(duì)turn執(zhí)行寫(xiě)操作(倒數(shù)第二行)之前
7、可能會(huì)觀察到第一個(gè)線(xiàn)程對(duì)intentFirst(倒數(shù)第一行)的寫(xiě)操作。關(guān)鍵詞volatile避免了這種情況,因?yàn)樗趯?duì)turn變量的寫(xiě)操作和對(duì)http://www.bjaccp.comintentFirst變量的寫(xiě)操作之間創(chuàng)建了一個(gè)先后關(guān)系。編譯器無(wú)法重新排序這些寫(xiě)操作,如果必要,它會(huì)利用一個(gè)內(nèi)存屏障禁止處理器重排序。讓我們來(lái)看看一些實(shí)現(xiàn)細(xì)節(jié)?! rintAssemblyHotSpot選項(xiàng)是JVM的一個(gè)診斷標(biāo)志,允許我們獲取JIT編譯器生成的匯編指令。這需要最新的OpenJDK版本或者新HotSpotupdate14或者更高版本。通過(guò)需
8、要一個(gè)反編譯插件。Kenai項(xiàng)目提供了用于Solaris、Linux和BSD的插件二進(jìn)制文件。hsdis是另一款可以在Windows通過(guò)源碼構(gòu)建的插件?! 纱雾樞蜃x操作的第一次(第三行)的匯