避免死锁
死锁是指两个或者多个线程在执行过程中,因争夺资源而造成的一种相互等待的现象。也就是说每个线程已经获取了其中一个对象上的锁,而且正在等待另一个对象上的错。考虑有两个线程和两个对象的情形,如下图所示。线程1获取object1上的锁,线程2获取object2上的锁,现在线程1等待object2上的锁,线程2等待object1上的锁。每个线程都在等待另一个线程释放它所需要的锁,导致两个线程都无法继续运行(死锁)。

死锁产生的四个必要条件
- 互斥条件:资源一次只能由一个线程占用
- 请求与保持条件:线程持有至少一个资源,并等待获取其它线程持有的资源
- 不剥夺条件:线程已获得的资源在未使用完之前不能被其它线程强行剥夺
- 循环等待条件:多个线程形成一种头尾相接的循环等待资源关系
示例:账户转账情形
package edu.cuit.avatar.concurrent; /** * @author <a href="mailto:1020zhaodan@163.com">Adan</a> * @version 1.0 * @date 2025/7/17 10:42 */ public class BankDeadLockDemo { private static class Account{ private String name; private int balance; public Account(String name, int balance) { this.name = name; this.balance = balance; } public int getBalance() { return balance; } public String getName() { return name; } public void deposit(int amount){ balance += amount; } public void withdraw(int amount){ balance -= amount; } @Override public String toString() { return name + ':' + balance; } } public static void transfer(Account from, Account to, int amount){ synchronized (from){ System.out.println(Thread.currentThread().getName() + " acquired lock on " + from); try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } synchronized (to){ System.out.println(Thread.currentThread().getName() + " acquired lock on " + to); if(from.balance >= amount){ from.withdraw(amount); to.deposit(amount); System.out.println("transfer successful!"); } else System.out.println("insufficient balance"); } } } public static void main(String[] args) { Account peppa = new Account("Peppa", 1000); Account jorge = new Account("jorge", 1000); new Thread(()-> transfer(peppa, jorge, 500)).start(); new Thread(()-> transfer(jorge, peppa, 500)).start(); } }
如何避免死锁
使用一种称为资源排序的简单技术可以轻易地避免死锁的发生。该技术是给每一个需要锁的对象指定一个顺序,确保每个线程都按照这个顺序来获取锁。例如,在上图中,假设按照object1,object2的顺序对两个对象进行排序。采用资源排序技术,线程2必须先获取object1上的锁,然后才能获取object2上的锁。一旦线程1获取了object1上的锁,线程2必须等待object1上的锁。所以,线程1就能获取object2上的锁,不会再发生死锁的现象。
使用资源排序技术解决上述转账问题
package edu.cuit.avatar.concurrent; /** * @author <a href="mailto:1020zhaodan@163.com">Adan</a> * @version 1.0 * @date 2025/7/17 10:42 */ public class BankDeadLockDemo { private static class Account{ private String name; private int balance; public Account(String name, int balance) { this.name = name; this.balance = balance; } public int getBalance() { return balance; } public String getName() { return name; } public void deposit(int amount){ balance += amount; } public void withdraw(int amount){ balance -= amount; } @Override public String toString() { return name + ':' + balance; } } public static void transfer(Account from, Account to, int amount){
//资源排序:确保所有线程以相同顺序获取锁 Account object1 = from.name.compareTo(to.name) < 0 ? from : to; Account object2 = object1 == from ? to : from; synchronized (object1){ System.out.println(Thread.currentThread().getName() + " acquired lock on " + from); try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } synchronized (object2){ System.out.println(Thread.currentThread().getName() + " acquired lock on " + to); if(from.balance >= amount){ from.withdraw(amount); to.deposit(amount); System.out.println("transfer successful!"); } else System.out.println("insufficient balance"); } } } public static void main(String[] args) { Account peppa = new Account("Peppa", 1000); Account jorge = new Account("jorge", 1000); new Thread(()-> transfer(peppa, jorge, 500)).start(); new Thread(()-> transfer(jorge, peppa, 500)).start(); } }
检测死锁
可以使用JDK工具检测死锁:
- 运行程序
- 使用jps命令查找java进程PID
- 使用jstack <pid>查看线程堆栈信息,进而了解死锁信息

浙公网安备 33010602011771号