首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 並發協作:死鎖形成與避免策略

     編輯:Java 相關知識

死鎖核心成因

死鎖發生於多線程互相持有對方需要的鎖,並等待對方釋放,形成循環等待。四個必要條件(Coffman 條件):

  1. 互斥條件:資源獨佔
  2. 請求與保持:持有資源又請求新資源
  3. 不剝奪條件:資源只能主動釋放
  4. 循環等待:線程鏈首尾相連

完整死鎖代碼示例

/** 
 * Java線程:並發協作-死鎖
 * @author Administrator
 */
public class Test {
    public static void main(String[] args) {
        DeadlockRisk dead = new DeadlockRisk();
        new MyThread(dead, 1, 2).start();
        new MyThread(dead, 3, 4).start();
        new MyThread(dead, 5, 6).start();
        new MyThread(dead, 7, 8).start();
    }
}

class MyThread extends Thread {
    private DeadlockRisk dead; private int a, b;
    MyThread(DeadlockRisk dead, int a, int b) { this.dead = dead; this.a = a; this.b = b; }
    @Override public void run() { dead.read(); dead.write(a, b); }
}

class DeadlockRisk {
    private static class Resource { public int value; }
    private Resource resourceA = new Resource();
    private Resource resourceB = new Resource();
    
    public int read() {
        synchronized (resourceA) {
            System.out.println("read():" + Thread.currentThread().getName() + "獲取了resourceA的鎖!");
            synchronized (resourceB) {
                System.out.println("read():" + Thread.currentThread().getName() + "獲取了resourceB的鎖!");
                return resourceB.value + resourceA.value;
            }
        }
    }
    
    public void write(int a, int b) {
        synchronized (resourceB) {  // 反序獲取鎖!
            System.out.println("write():" + Thread.currentThread().getName() + "獲取了resourceB的鎖!");
            synchronized (resourceA) {
                System.out.println("write():" + Thread.currentThread().getName() + "獲取了resourceA的鎖!");
                resourceA.value = a; resourceB.value = b;
            }
        }
    }
}

死鎖運行現象

死鎖截圖

程序卡住,無法繼續執行,控制台無新輸出。典型線程狀態:

  • 線程1:持有 resourceA,等待 resourceB
  • 線程2:持有 resourceB,等待 resourceA

死鎖避免與排查策略

  • 固定鎖獲取順序:所有線程按相同順序獲取多把鎖(如按 hashCode 排序)
  • 使用 tryLock 超時機制:ReentrantLock.tryLock(timeout) 避免無限等待
  • 縮小鎖範圍:減少持有鎖時間,降低衝突概率
  • 避免嵌套鎖:重構代碼,單一鎖完成操作
  • 排查工具:jstack、VisualVM、Arthas 分析線程堆棧定位死鎖

代碼修正示例:統一鎖順序

// 修正:read 和 write 都按 resourceA → resourceB 順序獲取鎖
public int read() {
    synchronized (resourceA) {
        synchronized (resourceB) { ... }
    }
}
public void write(int a, int b) {
    synchronized (resourceA) {  // 改為先鎖 A
        synchronized (resourceB) { ... }
    }
}

出處:https://lavasoft.blog.51cto.com/62575/222074

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved