2024-08-04  阅读(1)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/mianshi/baodian/detail/1754522811

回答

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

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

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

扩展

死锁演示

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

  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 完全够用了。


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文