鎖的狀態一共有四種:無鎖、偏向鎖、輕量級鎖、重量級鎖
鎖的狀態儲存在物件的標頭檔案中,以32位jdk為例:
鎖狀態25 bit
4bit
1bit
2bit
23bit
2bit
是否是偏向鎖
鎖標誌位
輕量級鎖
指向棧中鎖記錄的指標
00重量級鎖
指向互斥量(重量級鎖)的指標
10gc標記空11
偏向鎖線程id
epoch
物件分代年齡101
無鎖物件的hashcode
物件分代年齡001
鎖的初始為無所狀態,隨著鎖的競爭,鎖的公升級過程為: 偏向鎖 ---> 輕量級鎖--->重量級鎖,鎖的公升級是單向的,不會出現鎖的降級
(初始:無鎖狀態)
場景一、執行緒#1 獲取偏向鎖
1. 執行緒#1 訪問同步塊
2. 當前物件頭,鎖標誌位:01,是否是偏向鎖:0
3. cas更新mark word,設定偏向鎖標誌位1,設定執行緒id為執行緒#1的id
執行緒#1成功獲取偏向鎖,偏向鎖獲取成功後,執行緒不會主動釋放,即使執行緒執行完畢
場景二、執行緒#1擁有偏向鎖
1. 執行緒#1 又要訪問同步塊
2. 判斷鎖標誌位為01,是偏向鎖,判斷執行緒id是執行緒#1的id
3. 執行同步**
場景三、執行緒#2 競爭偏向鎖
1. 發現當前物件頭是偏向鎖
2. 判斷執行緒id是否為執行緒#2的id:否
3. 判斷執行緒#1是否還存在,不存在--->場景四,存在--->場景五
場景四、執行緒#2 競爭偏向鎖,執行緒#1 不存在,執行緒#2 獲取偏向鎖
1. 設定偏向鎖標誌位為0
2. 類似場景一,執行緒#2 獲取偏向鎖
場景五、執行緒#2 競爭偏向鎖,執行緒#1 存在,偏向鎖公升級為輕量級鎖
1. 到達全域性安全點(在這個時間點上沒有位元組碼正在執行),執行緒#1掛起
2. 設定鎖標誌位為00,將執行緒#1 的mark word複製到執行緒棧的lock record中,更新mark word,將mark word指向執行緒#1中monitor record的指標 (公升級為輕量級鎖)
3. 繼續執行執行緒#1 的**
4. 執行緒#2 自旋獲取鎖物件
場景六、執行緒#3競爭輕量級鎖
1. 拷貝物件頭的mark word到執行緒棧的lock record中
2. cas操作將mark word更新為指向lock record的指標,並將lock record裡的owner指標指向object mark word,成功--->3,失敗--->4
3. 更新成功,執行緒#3則獲取到了鎖
4. 更新失敗,檢查物件的mark word是否指向當前執行緒的棧幀,如果是則說明已經擁有該物件鎖,直接進入同步快執行。否則輕量級鎖膨脹為重量級鎖,mark word中儲存的是指向重量級鎖(互斥量)的指標
輕量級鎖cas操作之前堆疊與物件的狀態
輕量級鎖cas操作之後堆疊與物件的狀態
缺點適用場景
偏向鎖加鎖和解鎖不需要額外的消耗,和執行非同步方法比僅存在納秒級的差距。
如果執行緒間存在鎖競爭,會帶來額外的鎖撤銷的消耗。
只有乙個執行緒執行同步塊
輕量級鎖
競爭的執行緒不會阻塞,提高了程式的響應速度。
如果始終得不到鎖競爭的執行緒使用自旋會消耗cpu。
執行緒交替執行同步塊
追求響應時間。
同步塊執行速度非常快。
重量級鎖
執行緒競爭不使用自旋,不會消耗cpu。
執行緒阻塞,響應時間緩慢。
追求吞吐量。
同步塊執行速度較長。
參考文章:
偏向鎖,輕量級鎖,重量級鎖(java)
輕量級鎖是jdk 1.6之中加入的新型鎖機制,它名字中的 輕量級 是相對於使用作業系統互斥量來實現的傳統鎖而言的,因此傳統的鎖機制就稱為 重量級 鎖。首先需要強調一點的是,輕量級鎖並不是用來代替重量級鎖的,它的本意是在沒有多執行緒競爭的前提下,減少傳統的重量級鎖使用作業系統互斥量產生的效能消耗。要理...
偏向鎖 輕量級鎖 重量級鎖
首先簡單說下先偏向鎖 輕量級鎖 重量級鎖三者各自的應用場景 偏向鎖 只有乙個執行緒進入臨界區 輕量級鎖 多個執行緒交替進入臨界區 重量級鎖 多個執行緒同時進入臨界區。還要明確的是,偏向鎖 輕量級鎖都是jvm引入的鎖優化手段,目的是降低執行緒同步的開銷。比如以下的同步 塊 synchronized l...
偏向鎖 輕量級鎖 重量級鎖
synchronized關鍵字就像是汽車的自動檔,現在詳細講這個過程。一腳油門踩下去,synchronized會從無鎖公升級為偏向鎖,再公升級為輕量級鎖,最後公升級為重量級鎖,就像自動換擋一樣。那麼自旋鎖在 呢?這裡的輕量級鎖就是一種自旋鎖。初次執行到synchronized 塊的時候,鎖物件變成偏...