死锁(Dead Lock)示例
两个线程
- 线程1:先获取锁A,再获取锁B
- 线程2:先获取锁B,再获取锁A
package com.example.demo;
public class DeadLockExample {
public static void main(String[] args) {
Object lockA = new Object(); // 创建锁 A
Object lockB = new Object(); // 创建锁 B
// 创建线程 1
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockA) {
System.out.println("线程 1:获取到锁 A!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程 1:等待获取 B...");
synchronized (lockB) {
System.out.println("线程 1:获取到锁 B!");
}
}
}
});
t1.start(); // 运行线程
// 创建线程 2
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockB) {
System.out.println("线程 2:获取到锁 B!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程 2:等待获取 A...");
synchronized (lockA) {
System.out.println("线程 2:获取到锁 A!");
}
}
}
});
t2.start(); // 运行线程
}
}
程序会一直等待
线程 1:获取到锁 A!
线程 2:获取到锁 B!
线程 1:等待获取 B...
线程 2:等待获取 A...
解决方案1:顺序锁
两个线程
- 线程1:先获取锁A,再获取锁B
- 线程2:先获取锁A,再获取锁B
package com.example.demo;
public class SolveDeadLockExample {
public static void main(String[] args) {
Object lockA = new Object(); // 创建锁 A
Object lockB = new Object(); // 创建锁 B
// 创建线程 1
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockA) {
System.out.println("线程 1:获取到锁 A!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程 1:等待获取 B...");
synchronized (lockB) {
System.out.println("线程 1:获取到锁 B!");
}
}
}
});
t1.start(); // 运行线程
// 创建线程 2
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockA) {
System.out.println("线程 2:获取到锁 A!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程 2:等待获取B...");
synchronized (lockB) {
System.out.println("线程 2:获取到锁 B!");
}
}
}
});
t2.start(); // 运行线程
}
}
程序执行完成
线程 1:获取到锁 A!
线程 1:等待获取 B...
线程 1:获取到锁 B!
线程 2:获取到锁 A!
线程 2:等待获取B...
线程 2:获取到锁 B!
解决方案2:轮询锁
两个线程
- 线程1:先获取锁A,再获取锁B,如果失败,则释放所有锁
- 线程2:先获取锁B,再获取锁A
package com.example.demo;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SolveDeadLockExample {
public static void main(String[] args) {
Lock lockA = new ReentrantLock(); // 创建锁 A
Lock lockB = new ReentrantLock(); // 创建锁 B
// 创建线程 1(使用轮询锁)
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
// 调用轮询锁
pollingLock(lockA, lockB);
}
});
t1.start(); // 运行线程
// 创建线程 2
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
lockB.lock(); // 加锁
System.out.println("线程 2:获取到锁 B!");
try {
Thread.sleep(1000);
System.out.println("线程 2:等待获取 A...");
lockA.lock(); // 加锁
try {
System.out.println("线程 2:获取到锁 A!");
} finally {
lockA.unlock(); // 释放锁
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lockB.unlock(); // 释放锁
}
}
});
t2.start(); // 运行线程
}
/**
* 轮询锁
*/
public static void pollingLock(Lock lockA, Lock lockB) {
while (true) {
if (lockA.tryLock()) {
// 尝试获取锁
System.out.println("线程 1:获取到锁 A!");
try {
Thread.sleep(1000);
System.out.println("线程 1:等待获取 B...");
if (lockB.tryLock()) {
// 尝试获取锁
try {
System.out.println("线程 1:获取到锁 B!");
} finally {
lockB.unlock(); // 释放锁
System.out.println("线程 1:释放锁 B.");
break;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lockA.unlock(); // 释放锁
System.out.println("线程 1:释放锁 A.");
}
}
// 等待一秒再继续执行
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
程序执行完成
线程 1:获取到锁 A!
线程 2:获取到锁 B!
线程 1:等待获取 B...
线程 2:等待获取 A...
线程 1:释放锁 A.
线程 2:获取到锁 A!
线程 1:获取到锁 A!
线程 1:等待获取 B...
线程 1:获取到锁 B!
线程 1:释放锁 B.
线程 1:释放锁 A.
参考文章