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

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

1、對象頭中的Mark Word佈局java

 

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

2、偏向鎖的獲取過程(假設開啓了偏向鎖優化):性能優化

(1)初始時對象處於biasable狀態,而且ThreadID爲0即biasable & unbiased狀態(這裏不討論epoch和age)多線程

(2)當一個線程試圖鎖住一個處於biasable & unbiased狀態的對象時,經過一個CAS將本身的ThreadID放置到Mark Word中相應的位置,若是CAS操做成功進入第(3)步不然進入(4)步併發

(3)當進入到這一步時表明當前沒有鎖競爭,Object繼續保持biasable狀態,可是這時ThreadID字段被設置成了偏向鎖全部者的ID,而後進入到第(6)步oracle

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

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

(6)運行同步代碼塊性能

2、偏向鎖的解鎖過程:

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

 

3、參考資料:

相關文章
相關標籤/搜索