Java死鎖避免的五種方法舉例總結(jié)
前言
死鎖(Deadlock)是指多個(gè)線(xiàn)程互相持有對(duì)方需要的資源,導(dǎo)致所有線(xiàn)程都無(wú)法繼續(xù)執(zhí)行的情況。Java 中可以通過(guò)以下方法避免死鎖:
造成死鎖的?個(gè)原因:
?個(gè)資源每次只能被?個(gè)線(xiàn)程使?
?個(gè)線(xiàn)程在阻塞等待某個(gè)資源時(shí),不釋放已占有資源
?個(gè)線(xiàn)程已經(jīng)獲得的資源,在未使?完之前,不能被強(qiáng)?剝奪
若?線(xiàn)程形成頭尾相接的循環(huán)等待資源關(guān)系
這是造成死鎖必須要達(dá)到的4個(gè)條件,如果要避免死鎖,只需要不滿(mǎn)?其中某?個(gè)條件即可。?其中前3 個(gè)條件是作為鎖要符合的條件,所以要避免死鎖就需要打破第4個(gè)條件,不出現(xiàn)循環(huán)等待鎖的關(guān)系。
在開(kāi)發(fā)過(guò)程中:
要注意加鎖順序,保證每個(gè)線(xiàn)程按同樣的順序進(jìn)?加鎖
要注意加鎖時(shí)限,可以針對(duì)所設(shè)置?個(gè)超時(shí)時(shí)間
要注意死鎖檢查,這是?種預(yù)防機(jī)制,確保在第?時(shí)間發(fā)現(xiàn)死鎖并進(jìn)?解決
1. 死鎖產(chǎn)生的四個(gè)必要條件
要避免死鎖,首先要理解死鎖發(fā)生的條件(必須全部滿(mǎn)足):
互斥條件:資源一次只能被一個(gè)線(xiàn)程占用。
占有并等待:線(xiàn)程持有資源的同時(shí),等待其他資源。
不可搶占:線(xiàn)程持有的資源不能被其他線(xiàn)程強(qiáng)行奪走。
循環(huán)等待:多個(gè)線(xiàn)程形成環(huán)形等待鏈(A 等 B,B 等 C,C 等 A)。
只要破壞其中任意一個(gè)條件,就能避免死鎖!
2. 避免死鎖的 5 種方法
方法 1:按固定順序獲取鎖(破壞循環(huán)等待)
核心思想:所有線(xiàn)程按相同的順序申請(qǐng)鎖,避免循環(huán)依賴(lài)。
? 正確示例:
public void transfer(Account from, Account to, int amount) {
// 規(guī)定:先鎖 id 小的賬戶(hù),再鎖 id 大的賬戶(hù)
Account first = from.getId() < to.getId() ? from : to;
Account second = from.getId() < to.getId() ? to : from;
synchronized (first) {
synchronized (second) {
if (from.getBalance() >= amount) {
from.debit(amount);
to.credit(amount);
}
}
}
}為什么能避免死鎖?所有線(xiàn)程都按 id 順序加鎖,不會(huì)出現(xiàn) A 鎖 1 → 等 2 和 B 鎖 2 → 等 1 的情況。
方法 2:使用 tryLock + 超時(shí)(破壞占有并等待)
核心思想:如果拿不到鎖,就釋放已持有的鎖,避免無(wú)限等待。
? 正確示例(ReentrantLock):
public boolean transfer(Account from, Account to, int amount, long timeout) throws InterruptedException {
long startTime = System.currentTimeMillis();
while (true) {
if (from.lock.tryLock()) { // 嘗試獲取第一把鎖
try {
if (to.lock.tryLock()) { // 嘗試獲取第二把鎖
try {
if (from.getBalance() >= amount) {
from.debit(amount);
to.credit(amount);
return true;
}
} finally {
to.lock.unlock();
}
}
} finally {
from.lock.unlock(); // 釋放第一把鎖
}
}
// 超時(shí)檢查
if (System.currentTimeMillis() - startTime >= timeout) {
return false;
}
Thread.sleep(100); // 避免 CPU 忙等待
}
}優(yōu)點(diǎn):
不會(huì)無(wú)限等待,超時(shí)后可以重試或回滾。
適用于高并發(fā)場(chǎng)景(如支付系統(tǒng))。
方法 3:一次性申請(qǐng)所有資源(破壞占有并等待)
核心思想:使用一個(gè)全局鎖,一次性申請(qǐng)所有需要的資源。
? 正確示例:
public class AccountManager {
private static final Object globalLock = new Object();
public void transfer(Account from, Account to, int amount) {
synchronized (globalLock) { // 全局鎖保護(hù)所有賬戶(hù)
if (from.getBalance() >= amount) {
from.debit(amount);
to.credit(amount);
}
}
}
}缺點(diǎn):并發(fā)度降低(所有轉(zhuǎn)賬操作串行化)。
方法 4:使用 Lock 替代 synchronized(更靈活的控制)
ReentrantLock 比 synchronized 更靈活,可以避免死鎖:
Lock lock1 = new ReentrantLock();
Lock lock2 = new ReentrantLock();
public void methodA() {
boolean gotLock1 = false;
boolean gotLock2 = false;
try {
gotLock1 = lock1.tryLock(1, TimeUnit.SECONDS);
gotLock2 = lock2.tryLock(1, TimeUnit.SECONDS);
if (gotLock1 && gotLock2) {
// 執(zhí)行業(yè)務(wù)邏輯
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
if (gotLock1) lock1.unlock();
if (gotLock2) lock2.unlock();
}
}方法 5:檢測(cè)與恢復(fù)(允許死鎖發(fā)生,但能自動(dòng)恢復(fù))
適用于復(fù)雜系統(tǒng)(如數(shù)據(jù)庫(kù)、分布式系統(tǒng)):
1.檢測(cè)死鎖:
使用 ThreadMXBean 查找死鎖:
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long[] threadIds = bean.findDeadlockedThreads();
if (threadIds != null) {
System.out.println("檢測(cè)到死鎖!");
}2.恢復(fù)策略:
強(qiáng)制終止某個(gè)線(xiàn)程(如 thread.interrupt())。
回滾事務(wù)(數(shù)據(jù)庫(kù)場(chǎng)景)。
3. 死鎖案例分析
? 錯(cuò)誤代碼(會(huì)導(dǎo)致死鎖)
public void transfer(Account from, Account to, int amount) {
synchronized (from) { // 線(xiàn)程1:鎖 from → 等 to
synchronized (to) { // 線(xiàn)程2:鎖 to → 等 from
if (from.getBalance() >= amount) {
from.debit(amount);
to.credit(amount);
}
}
}
}死鎖場(chǎng)景:
線(xiàn)程1:
transfer(accountA, accountB, 100)線(xiàn)程2:
transfer(accountB, accountA, 200)結(jié)果:互相等待,死鎖!
4. 總結(jié)
| 方法 | 適用場(chǎng)景 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|---|
| 固定順序加鎖 | 簡(jiǎn)單鎖依賴(lài) | 實(shí)現(xiàn)簡(jiǎn)單 | 需要全局排序規(guī)則 |
| tryLock + 超時(shí) | 高并發(fā)系統(tǒng) | 避免無(wú)限等待 | 代碼復(fù)雜度高 |
| 全局鎖 | 低并發(fā)場(chǎng)景 | 絕對(duì)安全 | 性能差(串行化) |
| Lock 替代 synchronized | 需要更細(xì)粒度控制 | 靈活(可中斷、超時(shí)) | 需手動(dòng)釋放鎖 |
| 檢測(cè)與恢復(fù) | 數(shù)據(jù)庫(kù)、分布式系統(tǒng) | 適用于復(fù)雜場(chǎng)景 | 實(shí)現(xiàn)復(fù)雜 |
最佳實(shí)踐:
盡量用 tryLock + 超時(shí)(推薦
ReentrantLock)。如果必須用 synchronized,按固定順序加鎖。
避免嵌套鎖(如
synchronized里再調(diào)synchronized方法)。使用工具檢測(cè)死鎖(如
jstack、ThreadMXBean)。
到此這篇關(guān)于Java死鎖避免的五種方法的文章就介紹到這了,更多相關(guān)Java死鎖避免內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot整合freemarker 404問(wèn)題解決方案
這篇文章主要介紹了Springboot整合freemarker 404問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
SpringSecurity權(quán)限控制實(shí)現(xiàn)原理解析
這篇文章主要介紹了SpringSecurity權(quán)限控制實(shí)現(xiàn)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
SpringCloud-Hystrix實(shí)現(xiàn)原理總結(jié)
通過(guò)hystrix可以解決雪崩效應(yīng)問(wèn)題,它提供了資源隔離、降級(jí)機(jī)制、融斷、緩存等功能。接下來(lái)通過(guò)本文給大家分享SpringCloud-Hystrix實(shí)現(xiàn)原理,感興趣的朋友一起看看吧2021-05-05
Java中的字符型文件流FileReader和FileWriter詳細(xì)解讀
這篇文章主要介紹了Java中的字符型文件流FileReader和FileWriter詳細(xì)解讀,與字節(jié)型文件流不同,字節(jié)型文件流讀取和寫(xiě)入的都是一個(gè)又一個(gè)的字節(jié),而字符型文件流操作的單位是一個(gè)又一個(gè)的字符,字符型流認(rèn)為一個(gè)字母是一個(gè)字符,而一個(gè)漢字也是一個(gè)字符,需要的朋友可以參考下2023-10-10
Java操作MongoDB事務(wù)未生效的常見(jiàn)場(chǎng)景及解決方案
在 Java 開(kāi)發(fā)中,使用 MongoDB 存儲(chǔ)數(shù)據(jù)時(shí),事務(wù)的正確使用至關(guān)重要,然而,在實(shí)際開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)遇到 MongoDB 事務(wù)沒(méi)有生效的情況,本文我將結(jié)合多年實(shí)踐經(jīng)驗(yàn),深入剖析事務(wù)未生效的常見(jiàn)場(chǎng)景,并給出詳細(xì)的解決方案,需要的朋友可以參考下2025-07-07
SpringBoot快速實(shí)現(xiàn)IP地址解析的全攻略
在當(dāng)今的互聯(lián)網(wǎng)應(yīng)用中,IP地址解析已成為許多系統(tǒng)不可或缺的功能,這篇文章主要為大家詳細(xì)介紹了如何使用SpringBoot快速實(shí)現(xiàn)IP地址解析,有需要的小伙伴可以了解下2026-02-02
IntelliJ IDEA將導(dǎo)入的項(xiàng)目轉(zhuǎn)成maven項(xiàng)目
這篇文章主要介紹了IntelliJ IDEA將導(dǎo)入的項(xiàng)目轉(zhuǎn)成maven項(xiàng)目,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
MyBatis學(xué)習(xí)筆記(二)之關(guān)聯(lián)關(guān)系
這篇文章主要介紹了MyBatis學(xué)習(xí)筆記(二)之關(guān)聯(lián)關(guān)系 的相關(guān)資料,需要的朋友可以參考下2016-02-02

