线程死锁的定义
线程死锁是多线程编程里的一种问题,指的是两个或多个线程在执行过程中,因争夺资源而造成的一种互相等待的状态,在无外力作用时,这些线程都将无法继续执行下去。
例如,线程 A 持有资源 X 并请求资源 Y,而线程 B 持有资源 Y 并请求资源 X,这样两个线程就会陷入互相等待的状态,进而产生死锁。以下是一个简单的死锁示例代码:
public class DeadlockExample {
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: Holding resource 1...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 1: Waiting for resource 2...");
synchronized (resource2) {
System.out.println("Thread 1: Holding resource 1 and 2...");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (resource2) {
System.out.println("Thread 2: Holding resource 2...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 2: Waiting for resource 1...");
synchronized (resource1) {
System.out.println("Thread 2: Holding resource 1 and 2...");
}
}
});
thread1.start();
thread2.start();
}
}
在上述代码中,thread1
持有 resource1
并尝试获取 resource2
,而 thread2
持有 resource2
并尝试获取 resource1
,这样就可能导致死锁。
避免线程死锁的方法
1. 破坏互斥条件
互斥条件指的是资源在同一时间只能被一个线程使用。不过大部分资源本身就具有互斥性,所以通常很难破坏这一条件。
2. 破坏占有并等待条件
- 一次性获取所有资源:线程在开始执行前,一次性请求它所需要的全部资源,若无法获取所有资源,就等待,直到所有资源都可用。
public class AvoidDeadlockExample {
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) {
synchronized (resource2) {
System.out.println("Thread 1: Holding resource 1 and 2...");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (resource1) {
synchronized (resource2) {
System.out.println("Thread 2: Holding resource 1 and 2...");
}
}
});
thread1.start();
thread2.start();
}
}
3. 破坏不剥夺条件
当一个线程已经持有了某些资源,在它请求其他资源而无法立即获取时,它必须释放已持有的资源,等以后需要时再重新获取。例如使用 ReentrantLock
的 tryLock()
方法。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class AvoidDeadlockWithTryLock {
private static final Lock lock1 = new ReentrantLock();
private static final Lock lock2 = new ReentrantLock();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
while (true) {
if (lock1.tryLock()) {
try {
if (lock2.tryLock()) {
try {
System.out.println("Thread 1: Holding resource 1 and 2...");
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
}
});
Thread thread2 = new Thread(() -> {
while (true) {
if (lock2.tryLock()) {
try {
if (lock1.tryLock()) {
try {
System.out.println("Thread 2: Holding resource 1 and 2...");
} finally {
lock1.unlock();
}
}
} finally {
lock2.unlock();
}
}
}
});
thread1.start();
thread2.start();
}
}
4. 破坏循环等待条件
对资源进行排序,线程必须按照固定的顺序请求资源。这样就不会出现循环等待的情况。
public class AvoidDeadlockWithOrder {
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) {
synchronized (resource2) {
System.out.println("Thread 1: Holding resource 1 and 2...");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (resource1) {
synchronized (resource2) {
System.out.println("Thread 2: Holding resource 1 and 2...");
}
}
});
thread1.start();
thread2.start();
}
}
通过上述这些方法,可以有效避免线程死锁的发生。