Java线程面试题:什么是死锁?如何避免?
死锁是指两个或多个线程相互等待对方持有的锁而不能继续执行,造成代码无法向下进行的情况。以下是一个简单的例子:
public class DeadLockDemo { private static final Object lockA = new Object(); private static final Object lockB = new Object(); public static void main(String[] args) { Thread threadA = new MyThreadA(); Thread threadB = new MyThreadB(); threadA.start(); threadB.start(); } static class MyThreadA extends Thread { @Override public void run() { synchronized (lockA) { System.out.println("MyThreadA acquired lockA"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("MyThreadA is waiting for lockB..."); synchronized (lockB) { System.out.println("MyThreadA acquired lockB"); } } } } static class MyThreadB extends Thread { @Override public void run() { synchronized (lockB) { System.out.println("MyThreadB acquired lockB"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("MyThreadB is waiting for lockA..."); synchronized (lockA) { System.out.println("MyThreadB acquired lockA"); } } } } }
在这个例子中,我们创建了两个线程:MyThreadA和MyThreadB,分别竞争获取 lockA 和 lockB 这两个对象的锁。MyThreadA获取到了lockA 的锁,进入临界区并休眠1秒钟,然后试图获取 lockB 的锁;而 MyThreadB 获取到了lockB 的锁,也进入临界区并休眠1秒钟,然后试图获取 lockA 的锁。由于两个线程都在等待对方释放所持有的锁,因此出现了死锁情况。
避免死锁一般采用以下策略:
- 避免使用多个同步锁,尽量减少竞争情况;
- 保证获取锁的顺序,从而避免循环依赖;
- 使用定时锁来限制等待时间,超过一定时间后释放资源重新尝试获取。
修改代码如下:
public class DeadLockDemo { private static final Object lockA = new Object(); private static final Object lockB = new Object(); public static void main(String[] args) { Thread threadA = new MyThreadA(); Thread threadB = new MyThreadB(); threadA.start(); threadB.start(); } static class MyThreadA extends Thread { @Override public void run() { synchronized (lockA) { System.out.println("MyThreadA acquired lockA"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("MyThreadA is waiting for lockB..."); synchronized (lockB) { System.out.println("MyThreadA acquired lockB"); } } } } static class MyThreadB extends Thread { @Override public void run() { //保证获取锁的顺序,从而避免循环依赖 synchronized (lockA) { System.out.println("MyThreadB acquired lockA"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("MyThreadB is waiting for lockB..."); synchronized (lockB) { System.out.println("MyThreadB acquired lockB"); } } } } }
在 MyThreadB 中修改了竞争锁的获取顺序,使其先获取 lockA 的锁,从而解除了死锁情况。
总结:死锁是一种常见的并发问题,可以通过避免使用多个同步锁、保证获取锁的顺序和使用定时锁等策略来避免。在进行并发编程时,应当尽量避免出现死锁问题,以保障程序运行的稳定性和正确性。