輕量級鎖到底是怎麼回事啊啊啊啊

之前我們講了synchronized的原理(《且聽我一個故事講透一個鎖原理之synchronized》

),以及其中的偏向鎖(《偏向鎖到底是怎麼回事啊啊啊啊》),送佛送到西,這次我們來說一說輕量級鎖吧。

友情提醒:上面兩篇沒有看過的看官,請先閱讀上面兩篇之後,再讀此篇,這樣效果會更佳哦~


輕量級鎖到底是怎麼回事啊啊啊啊


開局一張圖。

看一張大圖

輕量級鎖到底是怎麼回事啊啊啊啊

輕量級鎖

流程講解

當JVM關閉了偏向鎖模式,對象在創建的時候,Mark Word中存儲的是hash值,年代,是否偏向鎖標誌位為0,標誌位是01。即一個無鎖不可偏向狀態。

輕量級鎖邏輯

1.當線程訪問同步塊,先判斷鎖狀態標誌位,如果是00,則說明是輕量級鎖,JVM會先在當前線程棧幀中分配Lock Record空間;

2.將鎖對象頭中的Mark Word拷貝到當前線程的Lock Record中,稱為Displaced Mark Word,然後使用CAS,將對象頭中的Mark Word修改為指向當前線程棧中Lock Record的指針(如圖)。如果成功,則獲取輕量級鎖,執行同步塊中的代碼,如果失敗,則進行自旋競爭鎖,自旋達到一定的次數如果依舊沒有獲取到鎖,則升級為重量級鎖(因為自旋會消耗CPU,為了避免無用的自旋,一旦鎖升級為重量級鎖,就不會恢復到輕量級鎖,自旋的線程會被掛起阻塞住);

輕量級鎖到底是怎麼回事啊啊啊啊

CAS操作之前堆棧與對象的狀態


輕量級鎖到底是怎麼回事啊啊啊啊

CAS操作之後堆棧與對象的狀態

3.執行完同步代碼塊代碼,退出同步代碼塊,使用CAS開始輕量級鎖解鎖,解鎖的條件需要滿足以下兩個:

1)對象頭Mark Word中鎖記錄指針是否依舊指向當前線程Lock Record

2)拷貝在當前線程Lock Record的Mark Word信息是否與對象頭中的Mark Word一致

4.如果滿足,則成功釋放鎖;

5.如果不滿足,則釋放鎖,喚醒被掛起阻塞的線程,開始重量級鎖的競爭。

注:當超過自旋閾值,競爭的線程就會把鎖對象Mark Word指向重量級鎖,導致Mark Word中的值發生了變化,當原持有輕量級鎖的線程執行完畢,嘗試通過CAS釋放鎖時,因為Mark Word已經指向重鎖,不再是指向當前線程Lock Record的指針,於是解鎖失敗,這時原持有輕量級鎖的線程就會知道鎖已經升級為重量級鎖。

偏向鎖升級為輕量級鎖:

1.先在原持有偏向鎖的線程棧幀中分配Lock Record;

2.將對象頭Mark Word拷貝到原持有偏向鎖的線程Lock Record中,然後使用CAS,將對象頭中的Mark Word修改為指向當前線程棧中Lock Record的指針。將原持有偏向鎖的線程升級為持有偏向鎖的線程;

3.喚醒線程,從安全點繼續執行,執行完畢解鎖。

輕量級鎖的重入計數

我們看個demo,在該demo中重複3次獲得鎖,

synchronized(obj){
synchronized(obj){
synchronized(obj){
}
}
}

假設鎖的狀態是輕量級鎖,如圖反應了Mark Word和線程棧中Lock Record的關係,右邊線程棧中包含3個指向當前鎖對象的Lock Record。其中棧中最高位的Lock Record為第一次獲取鎖時分配的,其中Displaced Mark word為鎖對象加鎖前的Mark Word,而之後的鎖重入,則會在線程棧中分配一個Displaced Mark word為null的Lock Record,用來重入計數。


輕量級鎖到底是怎麼回事啊啊啊啊

重入

每次釋放鎖的時候則會刪除對應的Lock Record。

這就是輕量級鎖的實現邏輯,相對於偏向鎖來說,邏輯會稍微簡單一些。

如果覺得學習到了,歡迎轉發加關注,那是我分享的動力呀~


分享到:


相關文章: