java中通过继承thread类演示死锁,需两个线程以相反顺序获取两个共享锁对象,如a先锁obj1再锁obj2、b先锁obj2再锁obj1,造成循环等待;运行后仅输出两行日志即僵持,jstack可确认死锁。

Java中通过继承Thread类构建死锁演示案例,核心在于让两个线程以相反顺序获取同一组锁,从而触发循环等待。这种方式直观、无需接口实现,适合教学和快速验证死锁机制。
明确锁对象与线程分工
死锁需要至少两个共享资源(如两个Object实例)和两个线程。每个线程必须按固定顺序尝试获取这两个锁,但彼此顺序相反:
- 线程A:先锁
obj1→ 再锁obj2 - 线程B:先锁
obj2→ 再锁obj1
这样当A持有obj1、B持有obj2后,双方都在等对方释放,形成僵持。
编写继承Thread的死锁线程类
定义两个独立的Thread子类,各自封装不同的加锁顺序:
class DeadlockThreadA extends Thread {
private final Object lock1, lock2;
public DeadlockThreadA(Object l1, Object l2) {
this.lock1 = l1;
this.lock2 = l2;
}
@Override
public void run() {
synchronized (lock1) {
System.out.println("A: 已获得 lock1");
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (lock2) {
System.out.println("A: 已获得 lock2");
}
}
}
}
class DeadlockThreadB extends Thread {
private final Object lock1, lock2;
public DeadlockThreadB(Object l1, Object l2) {
this.lock1 = l1;
this.lock2 = l2;
}
@Override
public void run() {
synchronized (lock2) {
System.out.println("B: 已获得 lock2");
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (lock1) {
System.out.println("B: 已获得 lock1");
}
}
}
}
启动并观察死锁现象
在main方法中创建共享锁对象,启动两个线程:
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = new Object();
new DeadlockThreadA(obj1, obj2).start();
new DeadlockThreadB(obj1, obj2).start();
}
运行后控制台通常只输出:
A: 已获得 lock1B: 已获得 lock2
之后程序无响应——说明两个线程均已阻塞,进入死锁状态。JVM不会报错,也不会自动恢复,需手动终止。
验证与调试小技巧
可通过jstack命令确认死锁(运行中执行jstack <pid></pid>):
- 输出中会明确出现
Found one Java-level deadlock:提示 - 列出各线程持有的锁及等待的锁,清晰对应上述逻辑
- 配合
Thread.currentThread().getName()打印线程名,便于日志追踪
注意:避免在sleep前加锁后立刻sleep,否则可能因执行过快而无法复现;100ms是较稳妥的间隔。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











