2024-08-04
版权声明:本文为博主原创文章,遵循 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 完全够用了。

阅读全文