官术网_书友最值得收藏!

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)境下保證共享變量的可見性。

主站蜘蛛池模板: 竹山县| 定远县| 克山县| 沅江市| 萍乡市| 屯门区| 平度市| 宾阳县| 嵩明县| 永清县| 大邑县| 哈巴河县| 五台县| 闽侯县| 仙游县| 阳东县| 白玉县| 买车| 大城县| 灵台县| 阜新| 文水县| 石楼县| 海原县| 陕西省| 安康市| 隆昌县| 新兴县| 铁岭市| 白玉县| 盐城市| 同仁县| 余干县| 武川县| 澄迈县| 日照市| 黄陵县| 揭阳市| 阿拉尔市| 临泽县| 新沂市|