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