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(); } }
在这个示例中,method1
和method2
分别由两个线程执行。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 } } }
避免死锁的关键在于仔细管理锁的顺序和释放,以确保线程不会陷入相互等待的循环中。在设计并发程序时,始终要考虑到线程间可能的锁交互,并采取适当的预防措施来避免死锁。