java排查死锁示例

目录
  • 死锁示例
  • 死锁产生原因
  • 死锁排查
    • 方案 1:jstack
    • 方案 2:jconsole
    • 方案 3:jvisualvm
    • 方案 4:jmc
  • 总结

死锁(Dead Lock)指的是两个或两个以上的运算单元(进程、线程或协程),都在等待对方停止执行,以取得系统资源,但是没有一方提前退出,就称为死锁。

死锁示例

接下来,我们先来演示一下 Java 中最简单的死锁,我们创建两个锁和两个线程,让线程 1 先拥有锁 A,然后在 1s 后尝试获取锁 B,同时我们启动线程 2,让它先拥有锁 B,然后在 1s 之后尝试获取锁 A,这时就会出现相互等待对方释放锁的情况,从而造成死锁的问题,具体代码如下:

public class DeadLockExample {
    public static void main(String[] args) {
        Object lockA = new Object(); // 创建锁 A
        Object lockB = new Object(); // 创建锁 B

        // 创建线程 1
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 先获取锁 A
                synchronized (lockA) {
                    System.out.println("线程 1:获取到锁 A!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 尝试获取锁 B
                    System.out.println("线程 1:等待获取 B...");
                    synchronized (lockB) {
                        System.out.println("线程 1:获取到锁 B!");
                    }
                }
            }
        });
        t1.start(); // 运行线程

        // 创建线程 2
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 先获取锁 B
                synchronized (lockB) {
                    System.out.println("线程 2:获取到锁 B!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 尝试获取锁 A
                    System.out.println("线程 2:等待获取 A...");
                    synchronized (lockA) {
                        System.out.println("线程 2:获取到锁 A!");
                    }
                }
            }
        });
        t2.start(); // 运行线程
    }
}

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

从上述结果可以看出,线程 1 和线程 2 都在等待对方释放锁,这样就造成了死锁问题。

死锁产生原因

通过以上示例,我们可以得出结论,要产生死锁需要满足以下 4 个条件

  1. 互斥条件:指运算单元(进程、线程或协程)对所分配到的资源具有排它性,也就是说在一段时间内某个锁资源只能被一个运算单元所占用。
  2. 请求和保持条件:指运算单元已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它运算单元占有,此时请求运算单元阻塞,但又对自己已获得的其它资源保持不放。
  3. 不可剥夺条件:指运算单元已获得的资源,在未使用完之前,不能被剥夺。
  4. 环路等待条件:指在发生死锁时,必然存在运算单元和资源的环形链,即运算单元正在等待另一个运算单元占用的资源,而对方又在等待自己占用的资源,从而造成环路等待的情况。

只有以上 4 个条件同时满足,才会造成死锁问题。

死锁排查

如果程序出现死锁问题,可通过以下 4 种方案中的任意一种进行分析和排查。

方案 1:jstack

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

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

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

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

PS:可以使用 jstack -help 查看更多命令使用说明。

方案 2:jconsole

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

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

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

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

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

方案 3:jvisualvm

jvisualvm 也在 JDK 的 bin 目录中,同样是双击打开:

稍等几秒之后,jvisualvm 中就会出现本地的所有 Java 程序,如下图所示:

双击选择要调试的程序:

单机鼠标进入“线程”模块,如下图所示:

从上图可以看出,当我们切换到线程一栏之后就会直接显示出死锁信息,之后点击“线程 Dump”生成死锁的详情信息,如下图所示:

方案 4:jmc

jmc 是 Oracle Java Mission Control 的缩写,是一个对 Java 程序进行管理、监控、概要分析和故障排查的工具套件。它也是在 JDK 的 bin 目录中,同样是双击启动,如下图所示:

jmc 主页信息如下:

之后选中要排查的程序,右键“启动 JMX 控制台”查看此程序的详细内容,如下图所示:

然后点击“线程”,勾中“死锁检测”就可以发现死锁和死锁的详情信息,如下图所示:

总结

死锁是因为两个或两个以上的运算单元,都在等待对方停止执行,以取得系统资源,但没有一方提前退出,于是就出现了死锁。死锁的排查工具总共有 4 种:

  • jstack
  • jconsole
  • jvisualvm
  • jmc

从易用性和性能方面来考虑,推荐使用 jconsole 或 jvisualvm 来排查死锁。

参考 & 鸣谢

blog.csdn.net/u010648555/article/details/80721815

cnblogs.com/cxuanBlog/p/13202898.html

zh.wikipedia.org/zh-hans/死锁

以上就是java排查死锁示例的详细内容,更多关于java排查死锁的资料请关注我们其它相关文章!

(0)

相关推荐

  • 浅谈Java由于不当的执行顺序导致的死锁

    我们来讨论一个经常存在的账户转账的问题.账户A要转账给账户B.为了保证在转账的过程中A和B不被其他的线程意外的操作,我们需要给A和B加锁,然后再进行转账操作, 我们看下转账的代码: public void transferMoneyDeadLock(Account from,Account to, int amount) throws InsufficientAmountException { synchronized (from){ synchronized (to){ transfer(fr

  • 浅谈java安全编码指南之死锁dead lock

    不同的加锁顺序 我们来看一个不同加锁顺序的例子: public class DiffLockOrder { private int amount; public DiffLockOrder(int amount){ this.amount=amount; } public void transfer(DiffLockOrder target,int transferAmount){ synchronized (this){ synchronized (target){ if(amount< tr

  • Java并发编程之死锁相关知识整理

    一.什么是死锁 所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进 二.死锁产生的条件 以下将介绍死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁 互斥条件 进程要求对所分配的资源(如打印机〉进行排他性控制,即在一段时间内某资源仅为一个进程所占有.此时若有其他进程请求该资源,则请求进程只能等待 不可剥夺条件 进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能

  • Java项目有中多个线程如何查找死锁

    当项目有中多个线程,如何查找死锁? 最近,在IDEA上进行多线程编程中老是在给线程加锁的时候,总是会遇到死锁问题,而当程序出现死锁问题时,编译器不能精确的显示错误的精确位置.当项目代码很多的时候, 往往会给自己添加不必要的麻烦,今天,我就分享分享几个解决方法. 1.编译环境 IDEA 2020 ,windows10, jdk8及以上版本 一.死锁是什么? 死锁指A线程想使用资源但是被B线程占用了,B线程线程想使用资源被A线程占用了,导致程序无法继续下去了. 1.1 死锁的例子: public c

  • Java检测死锁案例

    导致死锁的程序 package com.study.train; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.lang.reflect.Field; import java.util.*; import j

  • 如何解决Java多线程死锁问题

    死锁问题 死锁定义 多线程编程中,因为抢占资源造成了线程无限等待的情况,此情况称为死锁. 死锁举例 注意:线程和锁的关系是:一个线程可以拥有多把锁,一个锁只能被一个线程拥有. 当两个线程分别拥有一把各自的锁之后,又尝试去获取对方的锁,这样就会导致死锁情况的发生,具体先看下面代码: /** * 线程死锁问题 */ public class DeadLock { public static void main(String[] args) { //创建两个锁对象 Object lock1 = new

  • java排查死锁示例

    目录 死锁示例 死锁产生原因 死锁排查 方案 1:jstack 方案 2:jconsole 方案 3:jvisualvm 方案 4:jmc 总结 死锁(Dead Lock)指的是两个或两个以上的运算单元(进程.线程或协程),都在等待对方停止执行,以取得系统资源,但是没有一方提前退出,就称为死锁. 死锁示例 接下来,我们先来演示一下 Java 中最简单的死锁,我们创建两个锁和两个线程,让线程 1 先拥有锁 A,然后在 1s 后尝试获取锁 B,同时我们启动线程 2,让它先拥有锁 B,然后在 1s 之

  • Java多线程死锁示例

    本文实例演示了Java多线程死锁.分享给大家供大家参考,具体如下: package com.damlab.fz; public class DeadLock { public static void main(String[] args) { Resource r1 = new Resource(); Resource r2 = new Resource(); // 每个线程都拥有r1,r2两个对象 Thread myTh1 = new MyThread1(r1, r2); Thread myT

  • java线程死锁代码示例

    死锁是操作系统层面的一个错误,是进程死锁的简称,最早在 1965 年由 Dijkstra 在研究银行家算法时提出的,它是计算机操作系统乃至整个并发程序设计领域最难处理的问题之一. 事实上,计算机世界有很多事情需要多线程方式去解决,因为这样才能最大程度上利用资源,才能体现出计算的高效.但是,实际上来说,计算机系统中有很多一次只能由一个进程使用的资源的情况,例如打印机,同时只能有一个进程控制它.在多通道程序设计环境中,若干进程往往要共享这类资源,而且一个进程所需要的资源还很有可能不止一个.因此,就会

  • java实现死锁的示例代码

    什么是死锁 我们先看看这样一个生活中的例子:在一条河上有一座桥,桥面较窄,只能容纳一辆汽车通过,无法让两辆汽车并行.如果有两辆汽车A和B分别由桥的两端驶上该桥,则对于A车来说,它走过桥面左面的一段路(即占有了桥的一部分资源),要想过桥还须等待B车让出右边的桥面,此时A车不能前进:对于B车来说,它走过桥面右边的一段路(即占有了桥的一部分资源),要想过桥还须等待A车让出左边的桥面,此时B车也不能前进.两边的车都不倒车,结果造成互相等待对方让出桥面,但是谁也不让路,就会无休止地等下去.这种现象就是死锁

  • Java中死锁与活锁的具体实现

    目录 活锁与死锁 活锁 死锁 死锁的四个必要条件 互斥条件 请求和保持条件 不剥夺条件 环路等待条件 死锁示例 死锁排查 总结一下 如何避免死锁 预防死锁 设置加锁顺序 活锁示例 解决活锁 活锁与死锁 活锁 活锁同样会发生在多个相互协作的线程间,当他们为了彼此间的响应而相互礼让,使得没有一个线程能够继续前进,那么就发生了活锁.同死锁一样,发生活锁的线程无法继续执行. 相当于两个在半路相遇的人:出于礼貌他们相互礼让,避开对方的路,但是在另一条路上又相遇了.就这样,不停地一直避让下去.... 死锁

  • java避免死锁的常见方法代码解析

    死锁 索是一个非常有用的工具,运用场景非常多,因为它使用起来非常简单,而且易于理解.但同时它也会带来一些困扰,那就是可能会引起死锁,一旦产生死锁,就会造成系统功能不可用.让我们先来看一段代码,这段代码会引起死锁,使线程 thread_1 和线程 thread_2 互相等待对方释放锁. package thread; public class DeadLockDemo { private static String A = "A"; private static String B = &

  • Java线程死锁实例及解决方法

    这篇文章主要介绍了Java线程死锁实例及解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.死锁的定义 所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进 2.死锁产生的必要条件 互斥条件:线程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个线程所占有.此时若有线程请求该资源,则请求线程只能等待. 不剥夺条件:线程所获得的资源在未使用完毕之前,不能被其他线程倾向夺

  • Java多线程死锁问题详解(wait和notify)

    目录 一. synchronnized 的特性 1. 互斥性 2. 可重入性 二. 死锁问题 1. 什么是死锁 2. 死锁的四个必要条件 3. 常见的死锁场景及解决 3.1 不可重入造成的死锁 3.2 循环等待的场景 三. Object类中提供线程等待的方法 1. 常用方法 2. wait和notify的搭配使用 3. wait 和 sleep 的区别 4. 练习: 顺序打印ABC 总结 一. synchronnized 的特性 1. 互斥性 synchronized 会起到互斥效果, 这里的互

  • Java 线程死锁的问题解决办法

     Java 线程死锁的问题解决办法 [线程死锁]  原因:两个线程相互等待被对方锁定的资源 代码模拟: public class DeadLock { public static void main(String[] args) { Object obj = new Object(); Object obj1 = new Object(); DeadLockThread1 D1 = new DeadLockThread1(obj, obj1); DeadLockThread2 D2 = new

随机推荐