[Java復習] 面試突擊 - JVM


談談你對Java內存模型的理解?

Java內存模型8個指令:lock、unlock、read、load、use、assign、store、write

兩個線程同時執行data++;操作時,Java內存工作流程:

 

 

 

你知道Java內存模型中的原子性、可見性、有序性是什么?

連環炮 :Java內存模型 -> 原子性、可見性、有序性 -> volatile -> happens-before -> 內存屏障

 

原子性:線程1對i++時,線程2不能對i++同時進行。同時刻只有一個線程對一個值進行操作。

                 i++必須獨立執行,但默認時線程不安全的。

 

可見性:線程1操作i++后,強制線程2操作i時,必須從主內存中刷新更新后的i的值。

 

有序性:對於代碼,還有一個問題時指令重排序,編譯器和指令器,有時候為了提高代碼執行效率,會將指令重排序。

具備有序性,不會發生指令重排導致代碼異常;不具有有序性,會發生指令重排,導致代碼可能會出現一些問題。

 

能從Java底層角度聊聊volatile關鍵字的原理?

volatile用來解決可見性和有序性,在有些罕見條件下,可以有限保證原則性,但主要不是保證原則性的。

將volatile要從內存模型開始講起,還有原子性,可見性,有序性。

使其他工作線程內存中的值緩存失效,強制從主內存中讀取新值,即可見性。

在很多開源中間件系統源碼里都有多線程並發,大量使用volatile關鍵字。

 

指令重排以及happens-before原則是什么?

volatile關鍵字和有序性的關系,volatile是如何保證有序性的,如何避免發生指令重排的?

 

編譯器、指令器可能對代碼重排序,亂排,要遵守一定的規則,happens-before原則,只要符合happens-before的原則,那么就不能胡亂重排。

程序次序規則:一個線程內,按照代碼順序,書寫在前面的操作先行發生於書寫在后面的操作。

鎖定規則:一個unLock操作先行發生於后面對同一個鎖的lock操作,比如說在代碼里有先對一個lock.lock(),lock.unlock(),lock.lock()。

volatile變量規則:對一個volatile變量的寫操作先行發生於后面對這個volatile變量的讀操作,volatile變量寫,再是讀,必須保證是先寫,再讀。

傳遞規則:如果操作A先行發生於操作B,而操作B又先行發生於操作C,則可以得出操作A先行發生於操作C。

線程啟動規則:Thread對象的start()方法先行發生於此線程的每個一個動作,thread.start(),thread.interrupt()。

線程中斷規則:對線程interrupt()方法的調用先行發生於被中斷線程的代碼檢測到中斷事件的發生。

線程終結規則:線程中所有的操作都先行發生於線程的終止檢測,我們可以通過Thread.join()方法結束、Thread.isAlive()的返回值手段檢測到線程已經終止執行。

對象終結規則:一個對象的初始化完成先行發生於他的finalize()方法的開始。

 

      

 

 

用volatile來修飾flag后,一定可以讓prepare()指令在flag=true之前先執行,禁止指令重排。

 

參考資料:

互聯網Java工程師面試突擊(第三季)-- 中華石杉


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM