欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java死鎖避免的五種方法舉例總結(jié)

 更新時(shí)間:2025年05月07日 08:33:14   作者:EthanMilk  
這篇文章主要介紹了Java死鎖避免的五種方法,包括按固定順序加鎖、使用tryLock+超時(shí)、一次性申請(qǐng)所有資源、使用Lock替代synchronized以及檢測(cè)與恢復(fù),需要的朋友可以參考下

前言

死鎖(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)文章

  • 如何使用java判斷是不是數(shù)字

    如何使用java判斷是不是數(shù)字

    這篇文章主要給大家介紹了關(guān)于如何使用java判斷是不是數(shù)字的相關(guān)資料,判斷一個(gè)字符串是否為數(shù)字是Java開(kāi)發(fā)中很常見(jiàn)的業(yè)務(wù)需求,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • Java線(xiàn)程池?ThreadPoolExecutor?詳解

    Java線(xiàn)程池?ThreadPoolExecutor?詳解

    這篇文章主要介紹了Java線(xiàn)程池?ThreadPoolExecutor,線(xiàn)程池包括線(xiàn)程集合、阻塞隊(duì)列、拒絕策略處理器,更多相關(guān)內(nèi)容需要的朋友可以參考一下
    2022-07-07
  • SpringBoot 項(xiàng)目中的圖片處理策略之本地存儲(chǔ)與路徑映射

    SpringBoot 項(xiàng)目中的圖片處理策略之本地存儲(chǔ)與路徑映射

    在SpringBoot項(xiàng)目中,靜態(tài)資源存放在static目錄下,使得前端可以通過(guò)URL來(lái)訪(fǎng)問(wèn)這些資源,我們就需要將文件系統(tǒng)的文件路徑與URL建立一個(gè)映射關(guān)系,把文件系統(tǒng)中的文件當(dāng)成我們的靜態(tài)資源即可,本文給大家介紹SpringBoot本地存儲(chǔ)與路徑映射的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2023-12-12
  • 淺析SpringBoot自動(dòng)裝配的實(shí)現(xiàn)

    淺析SpringBoot自動(dòng)裝配的實(shí)現(xiàn)

    springboot開(kāi)箱即用,其實(shí)實(shí)現(xiàn)了自動(dòng)裝配,本文重點(diǎn)給大家介紹SpringBoot是如何做到自動(dòng)裝配的,感興趣的朋友跟隨小編一起看看吧
    2022-02-02
  • 關(guān)于二分法查找Java的實(shí)現(xiàn)及解析

    關(guān)于二分法查找Java的實(shí)現(xiàn)及解析

    這篇文章主要介紹了關(guān)于二分法查找Java的實(shí)現(xiàn)及解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • Java圖像處理教程之正片疊底效果的實(shí)現(xiàn)

    Java圖像處理教程之正片疊底效果的實(shí)現(xiàn)

    正片疊底效果是我們平時(shí)在Photoshop中會(huì)見(jiàn)到的一種效果,下面這篇文章主要給大家介紹了關(guān)于利用Java如何實(shí)現(xiàn)正片疊底的效果,分享出來(lái)供大家參考學(xué)習(xí),文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),需要的朋友可以參考借鑒,下面來(lái)一起看看詳細(xì)的介紹吧。
    2017-09-09
  • Java導(dǎo)出txt文件的方法

    Java導(dǎo)出txt文件的方法

    這篇文章主要介紹了Java導(dǎo)出txt文件的方法,實(shí)例分析了兩種java導(dǎo)出txt文本文件的使用技巧,需要的朋友可以參考下
    2015-05-05
  • 解決springboot 獲取form-data里的file文件的問(wèn)題

    解決springboot 獲取form-data里的file文件的問(wèn)題

    這篇文章主要介紹了解決springboot 獲取form-data里的file文件的問(wèn)題的相關(guān)資料,這里提供了詳細(xì)的解決步驟,需要的朋友可以參考下
    2017-07-07
  • 使用springMVC通過(guò)Filter實(shí)現(xiàn)防止xss注入

    使用springMVC通過(guò)Filter實(shí)現(xiàn)防止xss注入

    這篇文章主要介紹了使用springMVC通過(guò)Filter實(shí)現(xiàn)防止xss注入的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Springboot項(xiàng)目的搭建教程(分離出common父依賴(lài))

    Springboot項(xiàng)目的搭建教程(分離出common父依賴(lài))

    這篇文章主要介紹了Springboot項(xiàng)目的搭建教程(分離出common父依賴(lài)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01

最新評(píng)論