• 使用Jstack、Jconsole和jvisualvm进行死锁分析


    死锁概念:

    死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

    当程序执行过程中卡住时,排查下是否有死锁,可用小工具Jstack和Jconsole来进行死锁分析。

    1、使用Jstack进行死锁分析

    #首先通过jps查看当前运行的Java进程

    $jps

     #通过jstack分析死锁,可以查看到当前死锁详情

    jstack 24404

    Found one Java-level deadlock:

    =============================

    "Thread-1":

      waiting to lock monitor 0x000000001ca03578 (object 0x000000076c9fc6b0, a java.lang.String),

      which is held by "Thread-0"

    "Thread-0":

      waiting to lock monitor 0x000000001ca020d8 (object 0x000000076c9fc6e0, a java.lang.String),

      which is held by "Thread-1"

    Java stack information for the threads listed above:

    ===================================================

    "Thread-1":

            at runnable.DeadLockTest$2.run(DeadLockTest.java:48)

            - waiting to lock <0x000000076c9fc6b0> (a java.lang.String)

            - locked <0x000000076c9fc6e0> (a java.lang.String)

            at java.lang.Thread.run(Thread.java:748)

    "Thread-0":

            at runnable.DeadLockTest$1.run(DeadLockTest.java:33)

            - waiting to lock <0x000000076c9fc6e0> (a java.lang.String)

            - locked <0x000000076c9fc6b0> (a java.lang.String)

            at java.lang.Thread.run(Thread.java:748)

    Found 1 deadlock.

    2.使用Jconsole进行死锁分析

    2.1、首先启动死锁测试demo程序

    2.2、在cmd中运行jconsole打开图形化界面工具

    2.3、选择我们需要分析的进程进行连接

     2.4、选择线程选项,点击底部检测死锁功能

     2.5、再点击死锁,查看各线程的死锁情况

    3、使用jvisualvm进行死锁分析

    3.1、双击jvisualvm.exe弹出界面

    3.2、选择demo程序

     3、点击线程,进入线程页面

    4、选择Thread-1或Thread-0,点击线程Dump,进入页面,拉到最下面,可以看到

    Found 1 deadlock

    4、Java demo程序

    4.1、Demo例子

    1. package runnable;
    2. import org.omg.Messaging.SYNC_WITH_TRANSPORT;
    3. import java.util.Date;
    4. /**
    5. * ClassName DeadLockTest
    6. * description DeadLockTest
    7. *
    8. * @author : HMF
    9. * date: 2022/7/27 15:28
    10. **/
    11. public class DeadLockTest {
    12. private static String A="A";
    13. private static String B="B";
    14. public static void main(String[] args){
    15. new DeadLockTest().DeadLock();
    16. }
    17. public void DeadLock(){
    18. Thread t1=new Thread(new Runnable() {
    19. @Override
    20. public void run() {
    21. synchronized (A){
    22. try {
    23. Thread.sleep(1000);
    24. } catch (InterruptedException e) {
    25. e.printStackTrace();
    26. }
    27. synchronized (B){
    28. System.out.println("A");
    29. }
    30. }
    31. }
    32. });
    33. Thread t2=new Thread(new Runnable() {
    34. @Override
    35. public void run() {
    36. synchronized (B){
    37. try {
    38. Thread.sleep(1000);
    39. } catch (InterruptedException e) {
    40. e.printStackTrace();
    41. }
    42. synchronized (A){
    43. System.out.println("B");
    44. }
    45. }
    46. }
    47. });
    48. t1.start();
    49. t2.start();
    50. }
    51. }

    4.2、执行结果

    执行时效果(控制台无任何输出,但是代码在一直运行):

    4.3、死锁分析

    从上面代码中可以看出:是因为资源竞争的问题

    1. 线程t1先执行,锁住了A,等到t1要去锁B时,发现B已被t2锁住了,只能等待。
    2. 线程t2执行,锁住了B,等到t2要去锁A时,发现A已被t1锁住了,只能等待。

    最后两个线程互相等待,资源相互竞争,这就是死锁。

    4.4、如何避免死锁呢?

    查到有几个常见的方法

    1、避免一个线程同时获取多个锁。 ·

    2、避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。

    3、尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。 ·

    对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

    备注:

    分析java线程死锁的工具,推荐使用 jstack 命令,毕竟其他2个工具在Linux中是没有的。

    jstack 通过找到类入口,再找出当前线程正在等待哪个线程,然后再定位到死锁的行数。

  • 相关阅读:
    无服务架构--Serverless
    linux shell实现将文件中所有的小写字母转换为大写字母
    汽车汽配行业B2B电商平台系统:打通产业链数据信息流,增强企业竞争力
    创建一个自定义关卡资源(二)
    AVS感知无损压缩标准概述——视觉无损质量等级视频浅压缩
    764、最大加号标志
    只有程序员才能看懂的16张高端漫画
    提名 Apache ShardingSphere Committer,说说方法
    LeetCode每日一题——902. 最大为 N 的数字组合
    计算机网络 - IPv4 常考知识点详解(超详细!)
  • 原文地址:https://blog.csdn.net/fen_fen/article/details/126023772