什么是死锁?如何解决 Java 死锁问题

 作者简介:大家好,我是码炫码哥,前中兴通讯、美团架构师,现任某互联网公司CTO,兼职码炫课堂主讲源码系列专题


代表作:《jdk源码&多线程&高并发》,《深入tomcat源码解析》,《深入netty源码解析》,《深入dubbo源码解析》,《深入springboot源码解析》,《深入spring源码解析》,《深入redis源码解析》等


联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬。码炫课堂的个人空间-码炫码哥个人主页-面试,源码等

回答

死锁指的是两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,如果没有外力的帮助下,它们都将无法推进下去。简单的说就是两个或以上的进程都在互相等待对方释放资源,但是它们谁都不释放进程,系统就卡住了。

解决死锁的方法主要有以下几种:

  • 以确定的顺序获得锁:在获取锁的顺序上进行控制,确保所有线程获取锁的顺序是一致的,这样就可以预防死锁的产生。
  • 超时放弃:在获取锁的时候设置超时时间,如果在指定时间内未获取锁,我们可以做其他操作,避免死锁。比如使用 ReentrantLock 的 tryLock()
  • 监控和检测:使用一些死锁检测工具来检测线程是否发生了死锁,如果发现死锁,我们可以采取一些必要的措施,比如中断其中一个线程。
  • 避免嵌套锁:尽量避免一个线程同时持有多把锁

扩展

死锁演示

产生死锁有四个必要条件:

  1. 互斥条件:一个资源每次只能被一个进程使用。
  2. 占有并等待条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺,只能由该进程自己释放。
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

举一个例子:

public class DeadlockTest {
  private static final Object resourceA = new Object();
  private static final Object resourceB = new Object();

  public static void main(String[] args) {
    Thread thread1 = new Thread(() -> {
      synchronized (resourceA) {
        System.out.println(Thread.currentThread().getName() + "获取【资源 A】");
        try {
          Thread.sleep(500);
        } catch (InterruptedException e) {
          throw new RuntimeException(e);
        }

        synchronized (resourceB) {
          System.out.println(Thread.currentThread().getName() + "获取【资源 B】");
        }
      }
    });

    Thread thread2 = new Thread(() -> {
      synchronized (resourceB) {
        System.out.println(Thread.currentThread().getName() + "获取【资源 B】");
        try {
          Thread.sleep(50);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }

        synchronized (resourceA) {
          System.out.println(Thread.currentThread().getName() + "获取【资源 A】");
        }
      }
    });

    thread1.start();
    thread2.start();
  }
}

Thread-0 先锁住 resourceA,然后等待 resourceBThread-1 先锁住 resourceB,然后等待 resourceA,两个线程都在等待对方释放锁,然后他们就进入死锁状态了。

死锁排查

排查死锁的方式有几种,码哥一般都是直接使用 jstack 命令。

使用 jstack 命令排查死锁

首先,利用 jps 拿到当前 Java 应用程序的 pid

使用命令 jstack -l 42242,我们可以得到如下信息:

这图以一种非常清晰的方式告诉你,Thread-0 在等待哪个锁资源,这个资源被哪个线程持有,Thread-1 在等待哪个锁资源,这个资源被哪个线程持有。一目了然!!

当然,我们还可以使用其他的方式来检测、查看死锁,比如Java VisualVM,不过在实际应用过程中,jstack 完全够用了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值