JVM內部細節之二:偏向鎖(Biased Locking)


   在前面一片文章《JVM內部細節之一:synchronized關鍵字及實現細節》中已經提到過偏向鎖的概念,在理解什么是偏向鎖前必須先理解什么是輕量級鎖(Lightweight Locking)。引入偏向鎖是為了在無多線程競爭的情況下盡量減少不必要的輕量級鎖執行路徑,因為輕量級鎖的獲取及釋放依賴多次CAS原子指令,而偏向鎖只需要在置換ThreadID的時候依賴一次CAS原子指令(由於一旦出現多線程競爭的情況就必須撤銷偏向鎖,所以偏向鎖的撤銷操作的性能損耗必須小於節省下來的CAS原子指令的性能消耗)。下面看具體細節:

一、對象頭中的Mark Word布局

 

在上一篇文章中所討論的輕量級鎖中在我參考的Paper中對於重量級鎖的實現並沒有通過狀態位來表現而是直接通過在輕量級鎖的Monitor Record中關聯一個底層操作系統的互斥信號量來實現重量級鎖的操作(並不影響我們理解JVM內部鎖的運作過程),在偏向鎖的處理過程中並不涉及重量級鎖,我們這里只需要關心biasable和lightweight locked兩種狀態。在JDK1.6以后默認已經開啟了偏向鎖這個優化,我們可以通過在啟動JVM的時候加上-XX:-UseBiasedLocking參數來禁用偏向鎖(在存在大量鎖對象的創建並高度並發的環境下禁用偏向鎖能夠帶來一定的性能優化)。

二、偏向鎖的獲取過程(假設開啟了偏向鎖優化):

(1)初始時對象處於biasable狀態,並且ThreadID為0即biasable & unbiased狀態(這里不討論epoch和age)

(2)當一個線程試圖鎖住一個處於biasable & unbiased狀態的對象時,通過一個CAS將自己的ThreadID放置到Mark Word中相應的位置,如果CAS操作成功進入第(3)步否則進入(4)步

(3)當進入到這一步時代表當前沒有鎖競爭,Object繼續保持biasable狀態,但是這時ThreadID字段被設置成了偏向鎖所有者的ID,然后進入到第(6)步

(4)當前線程執行CAS獲取偏向鎖失敗(這一步是偏向鎖的關鍵),表示在該鎖對象上存在競爭並且這個時候另外一個線程獲得偏向鎖所有權。當到達全局安全點(safepoint)時獲得偏向鎖的線程被掛起,並從偏向鎖所有者的私有Monitor Record列表中獲取一個空閑的記錄,並將Object設置為LightWeight Lock狀態並且Mark Word中的LockRecord指向剛才持有偏向鎖線程的Monitor record,最后被阻塞在安全點的線程被釋放,進入到輕量級鎖的執行路徑中,同時被撤銷偏向鎖的線程繼續往下執行同步代碼。

(5)當一個線程試圖鎖住一個處於biasable & biased並且ThreadID不等於自己的ID時,這時由於存在鎖競爭必須進入到第(4)步來撤銷偏向鎖。

(6)運行同步代碼塊

二、偏向鎖的解鎖過程:

(1)偏向鎖解鎖過程很簡單,只需要測試下是否Object上的偏向鎖模式是否還存在,如果存在則解鎖成功不需要任何其他額外的操作。

 

三、參考資料:


免責聲明!

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



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