java定位死锁的三种方法(jstack、Arthas和Jvisualvm)

 更新时间:2021年09月06日 15:33:02   作者:baojh  
这篇文章主要给大家介绍了关于java定位死锁的三种方法,分别是通过jstack定位死锁信息、通过Arthas工具定位死锁以及通过 Jvisualvm 定位死锁,文中还介绍了死锁的预防方法,需要的朋友可以参考下

死锁

死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。

死锁发生的原因

死锁的发生是由于资源竞争导致的,导致死锁的原因如下:

  • 系统资源不足,如果系统资源充足,死锁出现的可能性就很低。
  • 进程(线程)运行推进的顺序不合适。
  • 资源分配不当等。

死锁发生的条件

死锁的发生的四个必要条件:

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

这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

1:通过jstack定位死锁信息

1.1:编写死锁代码

Lock lock1 = new ReentrantLock();
  Lock lock2 = new ReentrantLock();
  
  ExecutorService exectuorService = Executors.newFixedThreadPool(2);
  
  exectuorService.submit(() -> {
     lock1.lock();
     try{
         Thread.sleep(1000);
     }catch(Exception e){}
     try{}
     finally{
       lock1.unlock();
       lock2.unlock();
     }
  });
  exectuorService.submit(() -> {
     lock2.lock();
     try{
        Thread.sleep(1000);
     }catch(Exception e){}
     
     try{}
     finally{
         lock1.unlock();
         lock2.unlock();
     }
  });

1.2:查看死锁线程的pid

  • jps查看死锁的线程pid
  • 使用 jstack -l pid 查看死锁信息
  • 通过打印信息我们可以找到发生死锁的代码是在哪个位置
"DestroyJavaVM" #13 prio=5 os_prio=31 tid=0x00007f9a1d8fe800 nid=0xd03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
 - None

"pool-1-thread-2" #12 prio=5 os_prio=31 tid=0x00007f9a1d8fe000 nid=0xa703 waiting on condition [0x000070000ff8e000]
   java.lang.Thread.State: WAITING (parking)
 at sun.misc.Unsafe.park(Native Method)
 - parking to wait for  <0x0000000795768cd8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
 at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
 at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
 at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
 at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
 at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
 at com.coco.util.SlideTimeUnit.lambda$main$1(SlideTimeUnit.java:63)
 at com.coco.util.SlideTimeUnit$$Lambda$2/565760380.run(Unknown Source)
 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
 at java.util.concurrent.FutureTask.run(FutureTask.java:266)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
 at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
 - <0x0000000795768d08> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
 - <0x0000000795a9e4e0> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"pool-1-thread-1" #11 prio=5 os_prio=31 tid=0x00007f9a2082c800 nid=0xa803 waiting on condition [0x000070000fe8b000]
   java.lang.Thread.State: WAITING (parking)
 at sun.misc.Unsafe.park(Native Method)
 - parking to wait for  <0x0000000795768d08> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
 at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
 at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
 at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
 at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
 at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
 at com.coco.util.SlideTimeUnit.lambda$main$0(SlideTimeUnit.java:49)
 at com.coco.util.SlideTimeUnit$$Lambda$1/596512129.run(Unknown Source)
 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
 at java.util.concurrent.FutureTask.run(FutureTask.java:266)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
 at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
 - <0x0000000795768cd8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
 - <0x0000000795a9ba28> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"Service Thread" #10 daemon prio=9 os_prio=31 tid=0x00007f9a2082c000 nid=0x4103 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
 - None

"C1 CompilerThread3" #9 daemon prio=9 os_prio=31 tid=0x00007f9a1e021800 nid=0x3f03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

2:通过Arthas工具定位死锁

2.1: 下载好Arthas的jar,然后运行

有一个 thread -b 就可以查看到死锁信息

[arthas@4182]$ thread -b
"pool-1-thread-2" Id=12 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@2cb8a9a3 owned by "pool-1-thread-1" Id=11
    at sun.misc.Unsafe.park(Native Method)
    -  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@2cb8a9a3
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
    at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
    at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
    at com.coco.util.SlideTimeUnit.lambda$main$1(SlideTimeUnit.java:63)
    at com.coco.util.SlideTimeUnit$$Lambda$2/565760380.run(Unknown Source)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

    Number of locked synchronizers = 2
    - java.util.concurrent.ThreadPoolExecutor$Worker@6433a2
    - java.util.concurrent.locks.ReentrantLock$NonfairSync@3a855d13 <---- but blocks 1 other threads!

3. 通过 Jvisualvm 定位死锁

Jvisualvm 是一种自带的可视化工具,往往在在本地执行。

通过 Jvisualvm 命令打开软件,选中进程,进入线程视图,会给出死锁提示:

死锁的预防

  • 尽量避免使用多个锁,并且只有需要时才持有锁。
  • 如果使用多个锁,一定要设计好锁的获取顺序。
  • 使用带有超时的方法,为程序带来更多的可控性,比如指定获取锁的时间最多为5秒,超时就放弃。
  • 通过一些代码静态检查工具发现可能存在的死锁问题,比如FindBugs。

总结

到此这篇关于java定位死锁的文章就介绍到这了,更多相关java定位死锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java单例模式的知识点详解

    Java单例模式的知识点详解

    在本篇文章里小编给大家整理的是关于Java单例模式的知识点详解,有兴趣的朋友们可以学习参考下。
    2020-02-02
  • 使用IDEA进行安卓开发的详细图文教程

    使用IDEA进行安卓开发的详细图文教程

    安卓开发本身就是Java开发的一个分支,我们要确保计算机已经安装好JDK并做好了相关的配置,下面这篇文章主要给大家介绍了关于如何使用IDEA进行安卓开发的详细图文教程,需要的朋友可以参考下
    2023-04-04
  • Spring Cloud多个微服务之间调用代码实例

    Spring Cloud多个微服务之间调用代码实例

    这篇文章主要介绍了Spring Cloud多个微服务之间调用代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Graceful Response 构建 Spring Boot 响应处理的方法

    Graceful Response 构建 Spring Boot 响应

    Graceful Response是一个Spring Boot技术栈下的优雅响应处理器,提供一站式统一返回值封装、全局异常处理、自定义异常错误码等功能,本文介绍Graceful Response 构建 Spring Boot 下优雅的响应处理,感兴趣的朋友一起看看吧
    2024-01-01
  • 使用javax.validation.constraints对请求体进行统一校验

    使用javax.validation.constraints对请求体进行统一校验

    这篇文章主要介绍了使用javax.validation.constraints对请求体进行统一校验方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • springboot+kafka中@KafkaListener动态指定多个topic问题

    springboot+kafka中@KafkaListener动态指定多个topic问题

    这篇文章主要介绍了springboot+kafka中@KafkaListener动态指定多个topic问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • Java实现差分数组的示例详解

    Java实现差分数组的示例详解

    差分数组是由原数组进化而来,值为原数组当前位置值减去上一个位置的值。本文将通过例题详解如何利用Java实现差分数组,需要的可以参考一下
    2022-06-06
  • Spring 应用中集成 Apache Shiro的方法

    Spring 应用中集成 Apache Shiro的方法

    这篇文章主要介绍了Spring 应用中集成 Apache Shiro的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • swagger2隐藏在API文档显示某些参数的操作

    swagger2隐藏在API文档显示某些参数的操作

    这篇文章主要介绍了swagger2隐藏在API文档显示某些参数的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • maven repository详解

    maven repository详解

    这篇文章主要介绍了maven repository的相关知识,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05

最新评论