書中說可能會持續(xù)循環(huán)下去(看不到ready的新值,可見性), 也有可能輸出0(指令重排序)。
可見性的問題是由于ReaderThread線程可能會在工作內(nèi)存中緩存ready的值,在主線程更新完ready的值后,ReaderThread線程的工作內(nèi)存沒有得到刷新。
指令重排序的問題時由于注釋1處兩行代碼由于編譯器、處理器或Runtime的優(yōu)化,可能會發(fā)生顛倒,導(dǎo)致ReaderThread線程讀到了ready新值,此時卻沒有讀到number的新值。
但是在實際運行時,發(fā)現(xiàn)根本不會發(fā)生死循環(huán),也不會輸出0。原因可能是在現(xiàn)代多核處理器計算機上,代碼中主線程啟動完一個子線程后,主線程幾乎不會掛起而是繼續(xù)執(zhí)行,而新子線程的啟動又是需要一段時間的,所以代碼1中的指令總是先于新子線程的代碼。
因此,我在注釋2處讓主線程掛起1秒,確保子線程已經(jīng)啟動完成,即保證注釋1代碼晚于子線程代碼執(zhí)行。按理說此時ready變量不是volatile類型,主線程更新完ready的值后子線程應(yīng)該看不到才對,因此一直輸出3,但是在實際執(zhí)行代碼時,運行結(jié)果卻是程序正常退出,并且輸出number的新值42。按照網(wǎng)上說法,可能是jdk自身優(yōu)化了代碼,導(dǎo)致子線程可以看到主線程更新的ready新值。
雖然說實際運行代碼時沒有出現(xiàn)可見性或指令重排序的問題,但這并不表明代碼是正確的,程序仍然后風(fēng)險存在,要確保程序表現(xiàn)出正確性,成為線程安全的,還是需要使用volatile變量。
新聞熱點
疑難解答