Synchronized輕量級鎖原理

互聯網高級架構師 發佈 2022-12-25T04:01:48.254295+00:00

加鎖過程1.在線程棧中創建一個Lock Record,將其obj(即Object reference)欄位指向鎖對象。2.會把鎖的Mark Word複製到自己的Lock Record的Displaced Mark Word裡面。

加鎖過程

1.在線程棧中創建一個Lock Record,將其obj(即Object reference)欄位指向鎖對象。

2.會把鎖的Mark Word複製到自己的Lock Record的Displaced Mark Word裡面。然後線程嘗試直接通過CAS指令將Lock Record的地址存儲在對象頭的mark word中,如果對象處於無鎖狀態則修改成功,代表該線程獲得了輕量級鎖。如果失敗,進入到步驟3。

3.如果是當前線程已經持有該鎖了,代表這是一次鎖重入。設置Lock Record第一部分(Displaced Mark Word)為null,起到了一個重入計數器的作用。然後結束。

4.如果都失敗,表示Mark Word已經被替換成了其他線程的鎖記錄,說明在與其它線程競爭鎖,需要膨脹為重量級鎖。【這就是輕量級鎖升級為重量級鎖的時機】

解鎖過程

1.遍歷線程棧,找到所有obj欄位等於當前鎖對象的Lock Record。

2.如果Lock Record的Displaced Mark Word為null,代表這是一次重入,將obj設置為null後continue。

3.如果Lock Record的Displaced Mark Word不為null,則利用CAS指令將對象頭的mark word恢復成為Displaced Mark Word。如果成功,則continue,否則膨脹為重量級鎖。

輕量級鎖重入示例圖

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

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

輕量級鎖什麼時候升級為重量級鎖?

其實在加鎖的時候已經說過了,這裡再以一個具體場景說下

  • 線程1獲取輕量級鎖時會把鎖的Mark Word複製到自己的Lock Record的Displaced Mark Word裡面。然後線程嘗試直接通過CAS指令將Lock Record的地址存儲在對象頭的mark word中
  • 如果在線程1複製對象頭的同時(在線程1CAS之前),線程2也準備獲取鎖,複製了對象頭到線程2的鎖記錄空間中,但是在線程2在CAS的時候,發現線程1已經把對象頭換了,線程2的CAS失敗。那麼此時就代表發生了鎖競爭,準備升級為重量級鎖

輕量級鎖CAS的問題

1、結論: 沒有自旋這回事,只有重量級鎖獲取失敗才會自旋,網上的文章好多都是錯的,我個人認為輕量級鎖的意義就是在沒有線程爭用鎖時不用創建monitor。 【源碼得到的結論,實踐才是硬道理】

2、輕量級鎖和偏向鎖區別: 只要存在競爭就會升級重量級。輕量級鎖的存在就是用於線程之間交替獲取鎖的場景,但是和偏向鎖是有區別的啊。一個線程獲取偏向鎖之後,那麼這個鎖自然而然就屬於這個線程(就算該線程釋放了偏向鎖也不會改變這把鎖偏向這個線程的【也就是之前說的不會修改Thread ID】,這個前提是沒有發生過批量重偏向使鎖的epoch與其對應class類的epoch不相等)。所以說偏向鎖的場景是用於一個線程不斷的獲取鎖,如果把它放在輕量級鎖的場景下線程之間交替獲取的話會發生偏向鎖的撤銷的。也就是說在偏向鎖的情況下,線程1之前釋放了鎖,線程2再獲取鎖,即使此時沒有同時鎖競爭的情況,依然是要升級為輕量級鎖的。而輕量級鎖只要沒有同時去獲取鎖,就可以不升級為重量級鎖,也就代表你可以不同線程交替獲取這個鎖。

3、效率上來看偏向鎖只有在獲取的時候進行一次CAS,以後的釋放和獲取只需要簡單的一些判斷操作。而輕量級鎖的獲取和釋放都要都要CAS,單純的看效率還是偏向鎖效率高。

作者:別給我加香菜
連結:https://juejin.cn/post/7180175423006277688
來源:稀土掘金

關鍵字: