【操作系统】如何排查死锁?
创始人
2024-05-31 23:08:03

【操作系统】如何排查死锁?

文章目录

  • 【操作系统】如何排查死锁?
    • 死锁的概念
    • 死锁的排查工具
      • 排查工具 1:jstack
      • 排查工具 2:jconsole
    • 死锁的发生条件
      • 互斥条件
      • 持有并等待条件
      • 不可剥夺条件
      • 环路等待条件
    • 避免死锁问题的发生
    • 总结

死锁的概念

死锁(Dead Lock)指的是两个或两个以上的运算单元(进程、线程或协程),都在等待对方释放资源,但没有一方提起释放资源,从而造成了一种阻塞的现象就称为死锁。

比如线程 1 拥有了锁 A 的情况下试图获取锁 B,而线程 2 又在拥有了锁 B 的情况下试图获取锁 A,这样双方就进入相互阻塞等待的情况,如下图所示:

image-20230306134138304

死锁的代码实现如下:

/*** @description: 死锁* @author: blblccc* @date: 2023/3/6 13:41*/
public class DeadLockTest {public static Object A = new Object();public static Object B = new Object();public static void main(String[] args) {new Thread(() -> {synchronized (A) {try {System.out.println("线程1 抢占A");Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (B) {System.out.println("线程1 抢占B");}}}).start();new Thread(() -> {synchronized (B) {try {System.out.println("线程2 抢占B");Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (A) {System.out.println("线程2 抢占A");}}}).start();}
}

以上程序的执行结果如下图所示:

image-20230306134301153

从上述结果可以看出,线程 1 和线程 2 都在等待对方释放锁,这样就造成了死锁问题。 哪死锁应该如何排查呢?

死锁的排查工具

排查工具 1:jstack

在使用 jstack 之前,先要通过 jps 得到运行程序的进程 ID,使用方法如下:

image-20230306134331349

“jps -l”可以查询本机所有的 Java 程序,jps(Java Virtual Machine Process Status Tool)是 Java 提供的一个显示当前所有 Java 进程 pid 的命令,适合在 linux/unix/windows 平台上简单查看当前 Java 进程的一些简单情况,“-l”用于输出进程 pid 和运行程序完整路径名(包名和类名)。

有了进程 ID(PID)之后,我们就可以使用“jstack -l PID”来发现死锁问题了,如下图所示:

image-20230306134413119

jstack 用于生成 Java 虚拟机当前时刻的线程快照,“-l”表示长列表(long),打印关于锁的附加信息。

排查工具 2:jconsole

使用 jconsole 需要打开 JDK 的 bin 目录,找到 jconsole 并双击打开,如下图所示:

image-20230306134436609

然后选择要调试的程序,如下图所示:

image-20230306134452091

之后点击连接进入,选择“不安全的连接”进入监控主页,如下图所示:

image-20230306134505986

之后切换到“线程”模块,点击“检测死锁”按钮,如下图所示:

image-20230306134518790

之后稍等片刻就会检测出死锁的相关信息,如下图所示:

image-20230306134530534

死锁的发生条件

互斥条件

互斥条件是指多个线程不能同时使用同一个资源

比如下图,如果线程 A 已经持有的资源,不能再同时被线程 B 持有,如果线程 B 请求获取线程 A 已经占用的资源,那线程 B 只能等待,直到线程 A 释放了资源。

img

持有并等待条件

持有并等待条件是指,当线程 A 已经持有了资源 1,又想申请资源 2,而资源 2 已经被线程 C 持有了,所以线程 A 就会处于等待状态,但是线程 A 在等待资源 2 的同时并不会释放自己已经持有的资源 1

img

不可剥夺条件

不可剥夺条件是指,当线程已经持有了资源 ,在自己使用完之前不能被其他线程获取,线程 B 如果也想使用此资源,则只能在线程 A 使用完并释放后才能获取。

img

环路等待条件

环路等待条件指的是,在死锁发生的时候,两个线程获取资源的顺序构成了环形链

比如,线程 A 已经持有资源 2,而想请求资源 1, 线程 B 已经获取了资源 1,而想请求资源 2,这就形成资源请求等待的环形图。

img

避免死锁问题的发生

前面我们提到,产生死锁的四个必要条件是:互斥条件、持有并等待条件、不可剥夺条件、环路等待条件。

那么避免死锁问题就只需要破环其中一个条件就可以,最常见的并且可行的就是使用资源有序分配法,来破环环路等待条件

那什么是资源有序分配法呢?

线程 A 和 线程 B 获取资源的顺序要一样,当线程 A 是先尝试获取资源 A,然后尝试获取资源 B 的时候,线程 B 同样也是先尝试获取资源 A,然后尝试获取资源 B。也就是说,线程 A 和 线程 B 总是以相同的顺序申请自己想要的资源。

我们使用资源有序分配法的方式来修改前面发生死锁的代码,我们可以不改动线程 A 的代码。

我们先要清楚线程 A 获取资源的顺序,它是先获取互斥锁 A,然后获取互斥锁 B。

所以我们只需将线程 B 改成以相同顺序的获取资源,就可以打破死锁了。

img

总结

简单来说,死锁问题的产生是由两个或者以上线程并行执行的时候,争夺资源而互相等待造成的。

死锁只有同时满足互斥、持有并等待、不可剥夺、环路等待这四个条件的时候才会发生。

所以要避免死锁问题,就是要破坏其中一个条件即可,最常用的方法就是使用资源有序分配法来破坏环路等待条件。

相关内容

热门资讯

为非遗注入时尚力量 转自:贵州日报 权若青凯里“绣里淘”非遗集市,草木染的清香在空气中浮动,苗语叫卖声如古老歌谣在耳畔回...
贵州理工学院4门课程获批国家级... 转自:贵州日报 本报讯(记者 王雨)记者从贵州理工学院获悉,近日教育部发布《教育部关于公布第三批国家...
“贵州造”给煤矿安全装上“顺风... 转自:贵州日报贵州省能源智能开发与高效利用实验室。 张凌 摄 贵州日报天眼新闻记者 张凌在贵州深邃复...
一块钢板如何变为风力发电机组的... 转自:贵州日报贵州保龙设备制造有限公司风电塔筒生产车间内,工人对塔筒焊接口进行打磨。 贵州日报天眼新...
全国政协副主席王光谦率队到我省... 转自:贵州日报 本报讯(记者 鲁毅)1月8日至11日,全国政协副主席、民盟中央常务副主席王光谦率队到...