解讀synchronized鎖的釋放機(jī)制
synchronized鎖的釋放機(jī)制
synchronized 鎖的釋放機(jī)制是通過(guò) JVM 底層的 Monitor 鎖模型和 計(jì)數(shù)器機(jī)制 實(shí)現(xiàn)的。
以下是具體的釋放邏輯和觸發(fā)條件:
一、鎖釋放的觸發(fā)條件
正常執(zhí)行結(jié)束
當(dāng)線程執(zhí)行完 synchronized 修飾的代碼塊或方法時(shí),JVM 會(huì)自動(dòng)調(diào)用 monitorexit 指令釋放鎖。
- 同步代碼塊:通過(guò)
monitorenter和monitorexit指令顯式控制鎖的獲取與釋放。 - 同步方法:通過(guò)
ACC_SYNCHRONIZED標(biāo)志隱式觸發(fā)鎖的獲取和釋放,方法結(jié)束時(shí)自動(dòng)釋放鎖。
異常退出
- 如果在
synchronized代碼塊或方法中拋出未捕獲的異常,JVM 會(huì)執(zhí)行monitorexit指令釋放鎖。 - 編譯時(shí)會(huì)為同步代碼塊生成兩個(gè)
monitorexit指令:一個(gè)用于正常退出,另一個(gè)用于異常路徑。
顯式調(diào)用 wait()
- 線程在
synchronized代碼塊內(nèi)調(diào)用wait()方法時(shí) - 會(huì)暫時(shí)釋放鎖并進(jìn)入等待狀態(tài),直到其他線程調(diào)用
notify()/notifyAll()喚醒它
二、鎖釋放的核心機(jī)制
計(jì)數(shù)器遞減
- 每個(gè)對(duì)象關(guān)聯(lián)一個(gè) Monitor 鎖,內(nèi)部維護(hù)一個(gè)計(jì)數(shù)器(
_count)。 - 線程每次進(jìn)入
synchronized代碼塊時(shí)計(jì)數(shù)器加 1,退出時(shí)減 1。 - 當(dāng)計(jì)數(shù)器歸零時(shí),鎖完全釋放,其他線程可競(jìng)爭(zhēng)獲取。
Monitor 對(duì)象的狀態(tài)管理
- 持有鎖的線程(
_owner):釋放鎖后,_owner置為null,計(jì)數(shù)器歸零。 - 等待隊(duì)列(
_EntryList和_WaitSet):鎖釋放后,JVM 會(huì)從_EntryList或_WaitSet中喚醒線程重新競(jìng)爭(zhēng)鎖。
三、不同場(chǎng)景的鎖釋放示例
1. 同步代碼塊
public void method() {
synchronized (this) {
// 代碼邏輯
} // 此處自動(dòng)執(zhí)行 monitorexit 釋放鎖
}無(wú)論正常結(jié)束還是拋出異常,monitorexit 都會(huì)觸發(fā)鎖釋放。
2. 同步方法
public synchronized void method() {
// 代碼邏輯
} // 方法結(jié)束自動(dòng)釋放鎖通過(guò) ACC_SYNCHRONIZED 標(biāo)志隱式管理鎖,無(wú)需顯式字節(jié)碼指令。
3. 異常場(chǎng)景
public void method() {
synchronized (this) {
throw new RuntimeException(); // 觸發(fā)異常,自動(dòng)釋放鎖
}
}即使未捕獲異常,JVM 也會(huì)執(zhí)行 monitorexit 指令釋放鎖。
四、鎖釋放的底層實(shí)現(xiàn)(字節(jié)碼層面)
同步代碼塊
編譯后生成 monitorenter 和兩個(gè) monitorexit(正常退出和異常退出)指令:
public void method();
Code:
0: aload_0
1: dup
2: astore_1
3: monitorenter // 獲取鎖
4: ... // 業(yè)務(wù)代碼
13: monitorexit // 正常退出釋放鎖
14: goto 20
17: aload_1
18: monitorexit // 異常退出釋放鎖
19: athrow
20: return同步方法
方法訪問(wèn)標(biāo)志包含 ACC_SYNCHRONIZED,JVM 在方法入口和出口隱式管理鎖。
五、注意事項(xiàng)
不會(huì)釋放鎖的操作
Thread.sleep()、Thread.yield()不會(huì)釋放鎖。- 線程掛起(如
suspend())也不會(huì)釋放鎖。
可重入性
- 同一線程可多次獲取鎖(計(jì)數(shù)器遞增)
- 需對(duì)應(yīng)次數(shù)的退出操作才能完全釋放
總結(jié)
synchronized 鎖的釋放依賴(lài)于 JVM 的 Monitor 模型和計(jì)數(shù)器機(jī)制,通過(guò)以下方式觸發(fā):
- 代碼塊或方法正常結(jié)束。
- 未捕獲異常拋出。
- 顯式調(diào)用
wait()。 - 其底層通過(guò)
monitorexit指令或隱式標(biāo)志確保鎖的正確釋放,保障線程安全。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
設(shè)置JavaScript自動(dòng)提示-Eclipse/MyEclipse
自動(dòng)提示需要2個(gè)組件,分別是:ext-4.0.2a.jsb2||spket-1.6.16.jar,需要的朋友可以參考下2016-05-05
Java 中的vector和list的區(qū)別和使用實(shí)例詳解
在大家還沒(méi)有了解vector,list,deque的知識(shí)之前,我先給大家介紹下stl,本文重點(diǎn)給大家介紹vector和list的區(qū)別及使用,感興趣的的朋友一起看看吧2017-09-09
詳解RocketMQ 消費(fèi)端如何監(jiān)聽(tīng)消息
這篇文章主要為大家介紹了RocketMQ 消費(fèi)端如何監(jiān)聽(tīng)消息示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
java+testng+selenium的自動(dòng)化測(cè)試實(shí)例
這篇文章主要介紹了java+testng+selenium的自動(dòng)化測(cè)試實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
Java8函數(shù)式接口的基礎(chǔ)學(xué)習(xí)教程
這篇文章主要給大家介紹了關(guān)于Java8函數(shù)式接口基礎(chǔ)學(xué)習(xí)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04

