编写一个示例程序,展示如何产生多线程死锁的情况。
示例:多线程死锁
public class DeadlockExample {
private static final Object resource1 = new Object(); // 资源 1
private static final Object resource2 = new Object(); // 资源 2
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (resource1) {
System.out.println("Thread 1: Locked resource 1");
try {
// 模拟某些操作
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 1: Waiting to lock resource 2");
synchronized (resource2) {
System.out.println("Thread 1: Locked resource 2");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (resource2) {
System.out.println("Thread 2: Locked resource 2");
try {
// 模拟某些操作
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 2: Waiting to lock resource 1");
synchronized (resource1) {
System.out.println("Thread 2: Locked resource 1");
}
}
});
thread1.start();
thread2.start();
}
}
程序输出示例:
Thread 1: Locked resource 1
Thread 2: Locked resource 2
Thread 1: Waiting to lock resource 2
Thread 2: Waiting to lock resource 1
程序会卡在两个线程都等待对方释放锁的地方,形成死锁。
程序详解:
- 死锁的产生原因:
- 线程 1 持有
resource1
的锁,尝试获取resource2
的锁。 - 线程 2 持有
resource2
的锁,尝试获取resource1
的锁。 - 两个线程相互等待对方释放资源,导致死锁。
- 线程 1 持有
- 模拟死锁:
- 使用
Thread.sleep(100)
模拟资源占用时间,增加死锁发生的可能性。 - 线程 1 和线程 2 的锁定顺序不同(一个先锁定
resource1
再锁定resource2
,另一个相反),形成竞争条件。
- 使用
如何避免死锁?
- 始终按相同顺序获取锁: 确保所有线程都以固定顺序请求锁,可以避免循环等待。
修改代码:
public class DeadlockAvoidance { private static final Object resource1 = new Object(); private static final Object resource2 = new Object(); public static void main(String[] args) { Thread thread1 = new Thread(() -> { synchronized (resource1) { System.out.println("Thread 1: Locked resource 1"); synchronized (resource2) { System.out.println("Thread 1: Locked resource 2"); } } }); Thread thread2 = new Thread(() -> { synchronized (resource1) { // 修改为与线程 1 相同的锁顺序 System.out.println("Thread 2: Locked resource 1"); synchronized (resource2) { System.out.println("Thread 2: Locked resource 2"); } } }); thread1.start(); thread2.start(); } }
- 使用
tryLock()
(ReentrantLock): 使用java.util.concurrent.locks.ReentrantLock
,尝试获取锁,避免死锁。示例:
Lock lock1 = new ReentrantLock(); Lock lock2 = new ReentrantLock(); if (lock1.tryLock()) { try { if (lock2.tryLock()) { try { // 执行任务 } finally { lock2.unlock(); } } } finally { lock1.unlock(); } }
-
检测和处理死锁: 使用线程监控工具(如 JConsole 或 VisualVM)检测和分析死锁。