- Java并發(fā)編程深度解析與實戰(zhàn)
- 譚鋒(Mic)
- 704字
- 2022-05-10 18:39:19
3.1 關(guān)于線程的可見性問題分析
可見性和有序性是兩個獨立的問題,但是彼此又有關(guān)聯(lián),筆者將分別進行說明。
什么是可見性?如果一個線程對一個共享變量進行了修改,而其他線程不能及時地讀取修改之后的值,那么我們認為在多線程環(huán)境下該共享變量存在可見性問題,舉個具體的例子如下。

代碼的邏輯很簡單,首先t1線程通過stop變量來判斷是否應(yīng)該終止循環(huán),然后在main線程中通過修改stop變量的值來破壞t1線程的循環(huán)條件從而退出循環(huán)。但是,實際情況是t1線程并沒有按照期望的結(jié)果執(zhí)行,該線程一直處于運行狀態(tài)。
3.1.1 思考導(dǎo)致問題的原因
上述程序的問題只有在HotSpot的Server模式中才會出現(xiàn),在HotSpot虛擬機中內(nèi)置了兩個即時編譯器,分別是Client Compiler(C1編譯器)和Server Compiler(C2編譯器),程序使用哪個編譯器取決于JVM虛擬機的運行模式。
Server Compiler是專門面向服務(wù)器端的、充分優(yōu)化過的高級編譯器。它有一些比較典型的優(yōu)化功能,如無用代碼消除(Dead Code Elimination)、循環(huán)展開(Loop Unrolling)、循環(huán)表達式外提(Loop Expression Hoisting)、消除公共子表達式(Common Subexpression Elimination)等。下面我們在VolatileExample這個例子中,通過Server Compiler中的循環(huán)表達式外提(Loop Expression Hoisting)進行代碼優(yōu)化,具體如下。

從上面代碼中我們發(fā)現(xiàn),被優(yōu)化的代碼對stop變量不具備變化的能力,因此會導(dǎo)致當(dāng)其他線程修改stop的值時,該線程無法讀取。為了防止因JIT優(yōu)化而產(chǎn)生問題,我們可以增加一個JVM參數(shù):

再次運行VolatileExample程序,發(fā)現(xiàn)能夠正常執(zhí)行結(jié)束。但是通過JVM參數(shù)來禁止JIT優(yōu)化是全局的操作,會影響整個程序的優(yōu)化,代價有點大,有沒有更好的方式呢?
3.1.2 volatile關(guān)鍵字解決可見性問題
在Java中提供了一個volatile關(guān)鍵字,如果我們針對stop變量增加一個volatile關(guān)鍵字,并再次運行相同的代碼,就會發(fā)現(xiàn)t1線程能夠正常結(jié)束。

由此可見,volatile可以禁止編譯器的優(yōu)化,在多處理器環(huán)境下保證共享變量的可見性。
- 深入淺出WPF
- Learning Python Design Patterns(Second Edition)
- CouchDB and PHP Web Development Beginner’s Guide
- 精通Python自然語言處理
- PySide 6/PyQt 6快速開發(fā)與實戰(zhàn)
- Beginning C++ Game Programming
- Visual Basic程序設(shè)計(第三版)
- 從程序員角度學(xué)習(xí)數(shù)據(jù)庫技術(shù)(藍橋杯軟件大賽培訓(xùn)教材-Java方向)
- Monitoring Docker
- Learning Shiny
- ArcPy and ArcGIS(Second Edition)
- PHP從入門到精通(第7版)
- Scratch超人漫游記:創(chuàng)意程序設(shè)計:STEAM創(chuàng)新教育指南
- 開發(fā)者測試
- A/B 測試:創(chuàng)新始于試驗