一、monitor管程工作原理:
首先,synchronized是一個對象鎖,當線程運行到某個臨界區,這個臨界區使用synchronized對對象obj進行了上鎖,此時底層發生了什么?
1.當synchronized對obj上鎖后,synchronized會與操作系統層面的monitor管程建立連接,也就是在obj的header中構建一個指向monitor的指針。
2.此時線程訪問臨界區代碼,發現Obj鎖,所以去查看obj的header中的mark word中指向管程monitor的指針,從而找到monitor。線程會去查看monitor中的owner部分,訪問owner,如果owner目前沒有線程訪問,該線程成為owner去執行臨界區代碼段。如果存在owner,線程就被放進monitor中的entryset中,相當于等待隊列,等待執行完臨界區代碼段的線程的喚醒。
二、其中線程與obj的交互如下:
線程訪問臨界區后,會在棧幀中創建obj的指針以及lock record。
lockrecord中記錄著 當前鎖記錄的地址。
然后會與obj進行交互,嘗試使用cas將 lock record中的地址+鎖狀態 與 obj中的mark word交換。
如果交換成功,mark word 中存儲的lock狀態就會從00轉換為01,表示當前的obj為輕量級鎖。
現在的lock record中存放著obj 的 地址, 而 obj中也有到線程鎖記錄的地址。
完整流程:
首先需要明確,輕量級鎖不需要訪問monitor,因為與操作系統層面的monitor管程建立連接的花銷很高。
在線程之間沒有因為臨界區而交互時,此時掛載的是輕量級鎖。流程如下:
首先線程調用任何方法都會將該方法存放在方法區中,并且在線程的棧幀中保存該方法的局部變量、方法參數以及返回地址。
由于該方法有臨界區(加鎖),此時在線程的棧幀中還會維護鎖對象(synchronized是一個對象鎖,鎖住的對象需要創建對應的索引信息)的地址以及lock record(鎖記錄)用于存儲當前線程的地址。
同時會在棧幀中的額外槽位slot中維護鎖對象的header中的mark word(用于釋放鎖的還原)。
執行CAS 操作:構造一個新的 Mark Word:
-
低兩位改為
01
(輕量級鎖標志) -
高位填入指向自己棧幀 Lock Record 的地址
然后對對象頭做原子 CAS: -
成功 → 輕量級鎖加鎖成功,對象頭和 Lock Record 雙向鏈上了;
-
失敗 → 表示有另一個線程同時在搶這個鎖,進入自旋重試或鎖膨脹(升級到重量級鎖)。
解鎖的過程只需要再將棧幀中維護的舊對象頭替換回對象中即可。
當有其他線程發現鎖對象的鎖狀態不為00,此時就會進行后續處理,比如自旋,自旋失敗后,將后續的鎖升級為重量級鎖。