Java面試synchronized偏向鎖後hashcode存址

前言

今天的文章從下面這張圖片開始,這張圖片Java開發們應該很熟悉瞭

我們都知道無鎖狀態是對象頭是有位置存儲hashcode的,而變為偏向鎖狀態是沒有位置存儲hashcode的,今天我們來通過實現驗證這個問題:當鎖狀態為偏向鎖的時候,hashcode存到哪裡去瞭?

先說結論:

  • jdk8偏向鎖是默認開啟,但是是有延時的
    可通過參數: -XX:BiasedLockingStartupDelay=0關閉延時。
  • hashcode是懶加載,在調用hashCode方法後才會保存在對象頭中。
  • 當對象頭中沒有hashcode時,對象頭鎖的狀態是 可偏向( biasable,101,且無線程id)。
  • 如果在同步代碼塊之前調用hashCode方法,則對象頭中會有hashcode,且鎖狀態是 不可偏向(0 01),這時候再執行同步代碼塊,鎖直接是 輕量級鎖(thin lock,00)。

如果是在同步代碼塊中執行hashcode,則鎖是從 偏向鎖 直接膨脹為 重量級鎖。

1、hashcode是啥時候存進對象頭中?

根據下圖我們可知,hashcode並不是對象實例化後就創建,而是在調用默認的hasCode方法時才會放進對象頭。

第一次打印的對象頭中我們發現對象頭中mark word值為16進制的5,轉為2進制就是101,且後面的狀態顯示為biasable,也就是可偏向,註意區分可偏向和已偏向:可偏向表示還麼有synchronized鎖,已偏向表示有線程訪問鎖。

第二次打印對象頭中已經存在hashcode,value為0x00000039a054a501,轉換為2進制為:11100110100000010101001010010100000001,最後三位也就是0 01,這就表示不可偏向,也就說當出現synchronized鎖不會進行偏向,真是如此嗎?我們驗證一下!

2、存在hashcode後,出現synchronized會是什麼鎖?

根據下圖我們可以清晰的看到,當已存在hashcode再執行同步代碼,則會直接進入輕量級鎖,原因還是上面的結論,有hashcode後將鎖設置為 不可偏向,那肯定就直接上輕量級鎖咯。

3、如果鎖狀態是 已偏向,再計算hashcode會怎樣?

前面兩種情況鎖狀態都是 可偏向 狀態,如果此時鎖狀態是 已經進入偏向狀態呢?是會進行鎖升級嘛?

根據下圖我們可以看到,當hashCode方法處於synchronized代碼塊中時,鎖直接升級為重量級鎖。

至於為什麼直接升級為重量級鎖而不是輕量級鎖,這個原因不得而知。

豬哥猜想可能無線程競爭狀態下,偏向鎖升級為重量級鎖消耗的資源比輕量級鎖消耗的資源少。

同時歡迎知道原因的同學能夠留言告知,也歡迎大傢說出自己的猜想?沒準以後會根據你的方案優化呢!

4、總結

  • jdk8偏向鎖是默認開啟,但是是有延時的,可通過參數: -XX:BiasedLockingStartupDelay=0關閉延時。
  • hashcode是懶加載,在調用hashCode方法後才會保存在對象頭中。
  • 當對象頭中沒有hashcode時,對象頭鎖的狀態是 可偏向( biasable,101,且無線程id)。
  • 如果在同步代碼塊之前調用hashCode方法,則對象頭中會有hashcode,且鎖狀態是 不可偏向(0 01),這時候再執行同步代碼塊,鎖直接是 輕量級鎖(thin lock,00)。
  • 如果是在同步代碼塊中執行hashcode,則鎖是從 偏向鎖 直接膨脹為 重量級鎖。

以上就是Java面試synchronized偏向鎖後hashcode存址的詳細內容,更多關於java 偏向鎖hashcode存址的資料請關註WalkonNet其它相關文章!

推薦閱讀: