java死锁代码示例

死锁是指两个或更多线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法向前推进。

下面是一个简单的Java死锁示例,其中两个线程试图同时获取两个对象的锁,但每个线程都先获取一个对象的锁,然后等待另一个对象的锁,这就导致了死锁。

java复制代码
public class DeadLockDemo {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void method1() {
synchronized (lock1) {
System.out.println("Thread: " + Thread.currentThread().getId() + " has acquired lock 1...");
// A delay of 1 second to ensure thread scheduling
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread: " + Thread.currentThread().getId() + " is waiting to acquire lock 2...");
synchronized (lock2) {
System.out.println("Thread: " + Thread.currentThread().getId() + " has acquired lock 2...");
}
}
}
public void method2() {
synchronized (lock2) {
System.out.println("Thread: " + Thread.currentThread().getId() + " has acquired lock 2...");
// A delay of 1 second to ensure thread scheduling
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread: " + Thread.currentThread().getId() + " is waiting to acquire lock 1...");
synchronized (lock1) {
System.out.println("Thread: " + Thread.currentThread().getId() + " has acquired lock 1...");
}
}
}
public static void main(String[] args) {
final DeadLockDemo deadLockDemo = new DeadLockDemo();
// Thread 1
Thread thread1 = new Thread(() -> {
deadLockDemo.method1();
});
// Thread 2
Thread thread2 = new Thread(() -> {
deadLockDemo.method2();
});
// Start the threads
thread1.start();
thread2.start();
}
}

在这个示例中,method1method2分别由两个线程执行。method1首先获取lock1的锁,然后尝试获取lock2的锁。同时,method2首先获取lock2的锁,然后尝试获取lock1的锁。这就形成了一个死锁的情况,因为每个线程都在等待另一个线程释放它所需要的锁。

为了避免死锁,你需要确保线程以一致的顺序请求锁,或者设计你的程序以便当一个线程不能获取所有需要的锁时,它能够释放已经获取的锁。

避免死锁的一种常见策略是确保线程总是以相同的顺序请求锁。这样做可以打破循环等待的条件,从而防止死锁的发生。下面是一个修改后的代码示例,其中两个线程都以相同的顺序请求锁,这样就避免了死锁。

java复制代码
public class DeadLockAvoidedDemo {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void sharedMethod() {
synchronized (lock1) {
System.out.println("Thread: " + Thread.currentThread().getId() + " has acquired lock 1...");
// A delay of 1 second to ensure thread scheduling
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Thread: " + Thread.currentThread().getId() + " has acquired lock 2...");
// Perform shared operations on both locks here
}
}
}
public static void main(String[] args) {
final DeadLockAvoidedDemo deadLockAvoidedDemo = new DeadLockAvoidedDemo();
// Thread 1
Thread thread1 = new Thread(() -> {
deadLockAvoidedDemo.sharedMethod();
});
// Thread 2
Thread thread2 = new Thread(() -> {
deadLockAvoidedDemo.sharedMethod();
});
// Start the threads
thread1.start();
thread2.start();
}
}

在这个修改后的版本中,我们只有一个sharedMethod,它首先获取lock1的锁,然后获取lock2的锁。两个线程都调用这个sharedMethod,因此它们都会以相同的顺序请求锁。这样,即使两个线程同时运行,它们也不会进入死锁状态,因为每个线程都会在释放lock1之前获取lock2

即使我们确保了线程以相同的顺序请求锁,我们仍然需要谨慎处理锁的释放。如果线程在持有锁的情况下抛出异常,那么锁可能不会被正确释放,这可能导致其他线程被阻塞。最好是在finally块中释放锁,以确保在发生异常时也能正确释放锁。

java复制代码
public void sharedMethod() {
synchronized (lock1) {
try {
System.out.println("Thread: " + Thread.currentThread().getId() + " has acquired lock 1...");
// A delay of 1 second to ensure thread scheduling
Thread.sleep(1000);
synchronized (lock2) {
System.out.println("Thread: " + Thread.currentThread().getId() + " has acquired lock 2...");
// Perform shared operations on both locks here
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// This ensures that lock1 is released even if an exception is thrown
}
}
}

避免死锁的关键在于仔细管理锁的顺序和释放,以确保线程不会陷入相互等待的循环中。在设计并发程序时,始终要考虑到线程间可能的锁交互,并采取适当的预防措施来避免死锁。