天天看點

如果面試官讓你分析類初始化階段的死鎖現象

作者:JAVA後端架構
如果面試官讓你分析類初始化階段的死鎖現象

準備寫兩篇文章透徹剖析下類的初始化階段及初始化階段的死鎖問題:

  1. 類的初始化做什麼
  2. JVM底層是如何實作類的初始化的
  3. 為什麼會出現死鎖問題
  4. 怎麼解釋死鎖問題
  5. 如果證明你對死鎖的判斷是正确的
  6. 我是如何論證的

會由淺入深,循序漸進展開。今天是第一篇,難度偏認知層面。讀起來應該會很輕松愉快。

clinit

類初始化階段做什麼?其實很簡單,執行clinit方法。這個方法哪裡來的?你的Java代碼中隻要有靜态屬性或者是靜态代碼段,在編譯的時候就會自動生成這個方法。

代碼中有靜态屬性,如圖

如果面試官讓你分析類初始化階段的死鎖現象

代碼中有靜态方法,如圖

如果面試官讓你分析類初始化階段的死鎖現象

這段代碼有兩個地方需要注意下:1、靜态代碼塊前可以寫static,也可以不寫;2、如果代碼中有多個靜态代碼塊,編譯系統會合并成一個,合并後的代碼順序跟靜态代碼塊的先後順序儲存一緻。

死鎖現象

國際慣例,上代碼

如果面試官讓你分析類初始化階段的死鎖現象

這段代碼運作起來的結果,如圖

如果面試官讓你分析類初始化階段的死鎖現象

代碼永遠不會結束,其實在JVM層面,是發生了死鎖。

檢測死鎖

一提到死鎖,我們會馬上想起JVM提供的工具:jconsole、visualvm…期待的結果是

如果面試官讓你分析類初始化階段的死鎖現象

但是很遺憾,目前沒有工具能夠檢測出初始化階段發生的死鎖問題(我準備嘗試寫一個)。

為什麼jconsole檢測不到呢?看圖

如果面試官讓你分析類初始化階段的死鎖現象

線程根據執行代碼進入的空間來分,有這四種基本狀态,目前能看得到的工具,或者是JVM開放的API,隻能做到檢測出thread_in_Java這種狀态的線程死鎖問題。

是以這個問題隻能通過閱讀Hotspot源碼找答案。是以可以推測出面試官問你這個問題,就是看你有沒有這個能力,或者是這個習慣,通過閱讀Hotspot源碼找答案。

初始化流程

類的初始化階段,對應Hotspot源碼:InstanceKlass::initialize_impl。考慮到很多小夥伴不想看C++代碼,我用僞代碼把意思表達到

講兩個預備知識:

  1. 看這段代碼的時候要差別正在執行初始化的線程及其他線程。假設正在執行初始化的線程為T1,又進來一個線程T2執行初始化
  2. Hotspot源碼中此處有兩個狀态對了解代碼至關重要:being_initialized(正在執行初始化)、fully_initialized(完成初始化)
如果面試官讓你分析類初始化階段的死鎖現象

問題的答案已經很清晰了:

  1. 第一個線程執行new指令,觸發加載類A,然後執行A的初始化方法clinit,clinit方法中又執行到new指令,觸發加載類B,并執行類B的初始化方法clinit
  2. 第二個線程觸發加載類B,在類B的clinit方法中又觸發加載類A
  3. 死鎖的原因就是線程一跟線程二都進入了wait,也就是初始化流程的Step 2
  4. 其實這個問題存在時間差,如果某個線程跑得足夠快,完成了初始化,死鎖就不會發生。是以如果你的程式出現有時候卡着不動,有時候又是正常的,不妨大膽猜測有可能是發生了初始化階段死鎖。正常來講,出現死鎖的頻率更高,我測試了很多次,理想情況發生的次數還是很少很少的

然,目前得出的答案是從理論層面分析出來的,那事實是不是如此呢?如何證明呢?下篇文章分享。

為幫助開發者們提升面試技能、有機會入職BATJ等大廠公司,特别制作了這個專輯——這一次整體放出。

大緻内容包括了: Java 集合、JVM、多線程、并發程式設計、設計模式、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat等大廠面試題等、等技術棧!

如果面試官讓你分析類初始化階段的死鎖現象

歡迎大家關注公衆号【Java爛豬皮】,回複【666】,擷取以上最新Java後端架構VIP學習資料以及視訊學習教程,然後一起學習,一文在手,面試我有。

每一個專欄都是大家非常關心,和非常有價值的話題,如果我的文章對你有所幫助,還請幫忙點贊、好評、轉發一下,你的支援會激勵我輸出更高品質的文章,非常感謝!

如果面試官讓你分析類初始化階段的死鎖現象

作者:子牙 公号硬核子牙

出處:如果面試官讓你分析類初始化階段的死鎖現象 | HeapDump性能社群

繼續閱讀