JVM-多线程-死锁

jstack

        jstack 是一个Java命令行工具,用于打印Java应用程序的线程堆栈跟踪。它可以帮助开发者分析应用程序的线程状态,查找死锁或其他线程相关问题。

打印线程堆栈信息:jstack <PID>

2024-06-01 23:05:42
Full thread dump OpenJDK 64-Bit Server VM (17.0.2+8-86 mixed mode, sharing):

Threads class SMR info:
_java_thread_list=0x00000152f45f4780, length=15, elements={
0x00000152d9398f60, 0x00000152f37c0e10, 0x00000152f37c1c80, 0x00000152f37d9e00,
0x00000152f37db9c0, 0x00000152f37de480, 0x00000152f37dee30, 0x00000152f37dfbc0,
0x00000152f37e1990, 0x00000152f37e9cc0, 0x00000152f446e530, 0x00000152f4555430,
0x00000152f456bb90, 0x00000152f456e8a0, 0x00000152f37ab7b0
}

"main" #1 prio=5 os_prio=0 cpu=0.00ms elapsed=36.08s tid=0x00000152d9398f60 nid=0x8208 at breakpoint [0x00000027398ff000]
   java.lang.Thread.State: RUNNABLE
        at com.du.gc.YGCExample.main(YGCExample.java:22)

"Reference Handler" #2 daemon prio=10 os_prio=2 cpu=0.00ms elapsed=36.06s tid=0x00000152f37c0e10 nid=0x7a80 waiting on condition  [0x0000002739fff000]
   java.lang.Thread.State: RUNNABLE
        at java.lang.ref.Reference.waitForReferencePendingList(java.base@17.0.2/Native Method)
        at java.lang.ref.Reference.processPendingReferences(java.base@17.0.2/Reference.java:253)
        at java.lang.ref.Reference$ReferenceHandler.run(java.base@17.0.2/Reference.java:215)

"Finalizer" #3 daemon prio=8 os_prio=1 cpu=0.00ms elapsed=36.06s tid=0x00000152f37c1c80 nid=0x7f48 in Object.wait()  [0x000000273a0ff000]       
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(java.base@17.0.2/Native Method)
        - waiting on <0x00000000fff0d5c8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(java.base@17.0.2/ReferenceQueue.java:155)
        - locked <0x00000000fff0d5c8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(java.base@17.0.2/ReferenceQueue.java:176)
        at java.lang.ref.Finalizer$FinalizerThread.run(java.base@17.0.2/Finalizer.java:172)

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 cpu=0.00ms elapsed=36.05s tid=0x00000152f37d9e00 nid=0xaa60 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" #5 daemon prio=5 os_prio=2 cpu=0.00ms elapsed=36.05s tid=0x00000152f37db9c0 nid=0xa6e4 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Service Thread" #6 daemon prio=9 os_prio=0 cpu=0.00ms elapsed=36.05s tid=0x00000152f37de480 nid=0xb090 runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Monitor Deflation Thread" #7 daemon prio=9 os_prio=0 cpu=0.00ms elapsed=36.05s tid=0x00000152f37dee30 nid=0x8108 runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #8 daemon prio=9 os_prio=2 cpu=0.00ms elapsed=36.05s tid=0x00000152f37dfbc0 nid=0x6dc4 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   No compile task

"C1 CompilerThread0" #16 daemon prio=9 os_prio=2 cpu=0.00ms elapsed=36.05s tid=0x00000152f37e1990 nid=0x3e84 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   No compile task

"Sweeper thread" #20 daemon prio=9 os_prio=2 cpu=0.00ms elapsed=36.05s tid=0x00000152f37e9cc0 nid=0xa21c runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Common-Cleaner" #21 daemon prio=8 os_prio=1 cpu=0.00ms elapsed=36.01s tid=0x00000152f446e530 nid=0x52d0 in Object.wait()  [0x000000273a8fe000] 
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
        at java.lang.Object.wait(java.base@17.0.2/Native Method)
        - waiting on <0x00000000ffe39bc8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(java.base@17.0.2/ReferenceQueue.java:155)
        - locked <0x00000000ffe39bc8> (a java.lang.ref.ReferenceQueue$Lock)
        at jdk.internal.ref.CleanerImpl.run(java.base@17.0.2/CleanerImpl.java:140)
        at java.lang.Thread.run(java.base@17.0.2/Thread.java:833)
        at jdk.internal.misc.InnocuousThread.run(java.base@17.0.2/InnocuousThread.java:162)

"JDWP Transport Listener: dt_socket" #22 daemon prio=10 os_prio=0 cpu=0.00ms elapsed=35.99s tid=0x00000152f4555430 nid=0x72b4 runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"JDWP Event Helper Thread" #23 daemon prio=10 os_prio=0 cpu=0.00ms elapsed=35.99s tid=0x00000152f456bb90 nid=0x9f68 runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"JDWP Command Reader" #24 daemon prio=10 os_prio=0 cpu=0.00ms elapsed=35.99s tid=0x00000152f456e8a0 nid=0x3dd4 runnable  [0x0000000000000000]   
   java.lang.Thread.State: RUNNABLE

"Notification Thread" #25 daemon prio=9 os_prio=0 cpu=0.00ms elapsed=35.69s tid=0x00000152f37ab7b0 nid=0x49e0 runnable  [0x0000000000000000]    
   java.lang.Thread.State: RUNNABLE

"VM Thread" os_prio=2 cpu=0.00ms elapsed=36.07s tid=0x00000152f37ba200 nid=0xb7f8 runnable

"GC Thread#0" os_prio=2 cpu=0.00ms elapsed=36.07s tid=0x00000152d93b9a40 nid=0x2658 runnable

"G1 Main Marker" os_prio=2 cpu=0.00ms elapsed=36.07s tid=0x00000152d93bd9a0 nid=0x9ac8 runnable

"G1 Conc#0" os_prio=2 cpu=0.00ms elapsed=36.07s tid=0x00000152d93be3b0 nid=0xac44 runnable

"G1 Refine#0" os_prio=2 cpu=0.00ms elapsed=36.07s tid=0x00000152d944e5e0 nid=0x4778 runnable

"G1 Service" os_prio=2 cpu=0.00ms elapsed=36.07s tid=0x00000152f3684210 nid=0xb300 runnable

"VM Periodic Task Thread" os_prio=2 cpu=0.00ms elapsed=35.69s tid=0x00000152d93de9e0 nid=0xb750 waiting on condition

JNI global refs: 767, weak refs: 0

远程连接

 jstack -l <hostname>:<port>

        这里的 <hostname> 是远程服务器的地址,<port> 是JVM的JMX端口号,通常在启动Java应用时通过 -Dcom.sun.management.jmxremote.port=<port> 参数指定。

 应用

  1. 死锁,Deadlock(重点关注)
  2. 等待资源,Waiting on condition(重点关注)
  3. 等待获取监视器,Waiting on monitor entry(重点关注)
  4. 阻塞,Blocked(重点关注)
  5. 执行中,Runnable
  6. 暂停,Suspended
  7. 对象等待中,Object.wait或TIMED_WAITING
  8. 停止,Parked

案例-死锁

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

产生死锁主要原因

  1. 系统资源不足
  2. 进程运行推进的顺序不合适
  3. 资源分配不当

示例

public class DeadLockDemo {
  static Object lockA = new Object();
  static Object lockB = new Object();


  public static void main(String[] args) {

    Thread a = new Thread(() -> {
      synchronized (lockA) {
        System.out.println(Thread.currentThread().getName() + "\t" + " 自己持有A锁,期待获得B锁");

        try {
          TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }

        //锁b 已被其他线程持有
        synchronized (lockB) {
          System.out.println(Thread.currentThread().getName() + "\t 获得B锁成功");
        }
      }
    }, "a");
    a.start();

    new Thread(() -> {
      synchronized (lockB) {
        System.out.println(Thread.currentThread().getName() + "\t" + " 自己持有B锁,期待获得A锁");

        try {
          TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }

        //锁A 已被其他线程持有
        synchronized (lockA) {
          System.out.println(Thread.currentThread().getName() + "\t 获得A锁成功");
        }
      }
    }, "b").start();
  }
}

try lock 避免死锁

public class TryLockDeadlock implements Runnable {


  int flag = 1;
  static Lock lock1 = new ReentrantLock();
  static Lock lock2 = new ReentrantLock();

  public static void main(String[] args) {
    TryLockDeadlock r1 = new TryLockDeadlock();
    TryLockDeadlock r2 = new TryLockDeadlock();
    r1.flag = 0;
    new Thread(r1).start();
    new Thread(r2).start();

  }

  @Override
  public void run() {
    for (int i = 0; i < 100; i++) {
      if (flag == 1) {
        try {
          if (lock1.tryLock(800, TimeUnit.MILLISECONDS)) {
            try {
              System.out.println("线程1获取到了锁1");
              Thread.sleep(new Random().nextInt(1000));
              if (lock2.tryLock(800, TimeUnit.MILLISECONDS)) {
                try {
                  System.out.println("线程1获取到了锁2");
                  System.out.println("线程1成功获取到了两把锁");
                  break;
                } finally {
                  lock2.unlock();
                }
              } else {
                System.out.println("线程1获取锁2失败,已重试");
              }
            } finally {
              lock1.unlock();
              Thread.sleep(new Random().nextInt(1000));
            }
          } else {
            System.out.println("线程1获取锁1失败,已重试");
          }
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }

      if (flag == 0) {
        try {
          if (lock2.tryLock(3000, TimeUnit.MILLISECONDS)) {
            try {
              System.out.println("线程2获取到了锁2");
              Thread.sleep(new Random().nextInt(1000));
              if (lock1.tryLock(800, TimeUnit.MILLISECONDS)) {
                try {
                  System.out.println("线程2获取到了锁1");
                  System.out.println("线程2成功获取到了两把锁");
                  break;
                } finally {
                  lock1.unlock();
                }
              } else {
                System.out.println("线程2获取锁1失败,已重试");
              }
            } finally {
              lock2.unlock();
              Thread.sleep(new Random().nextInt(1000));
            }
          } else {
            System.out.println("线程2获取锁2失败,已重试");
          }
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }
}

3. 排查

 jps -l

死锁的类,进程号

 jstack 进程编号

Found one Java-level deadlock:
=============================
"Thread-0":
  waiting to lock monitor 0x00000218c5626e30 (object 0x0000000629237040, a java.lang.Object),
  which is held by "Thread-1"

"Thread-1":
  waiting to lock monitor 0x00000218c5625770 (object 0x0000000629237030, a java.lang.Object),
  which is held by "Thread-0"

Java stack information for the threads listed above:
===================================================
"Thread-0":
        at com.du.cpu.JstackDeadLockDemo.calLock_Obj1_First(JstackDeadLockDemo.java:36)
        - waiting to lock <0x0000000629237040> (a java.lang.Object)
        - locked <0x0000000629237030> (a java.lang.Object)
        at com.du.cpu.JstackDeadLockDemo.lambda$testDeadlock$0(JstackDeadLockDemo.java:22)
        at com.du.cpu.JstackDeadLockDemo$$Lambda$14/0x0000000800c01208.run(Unknown Source)
        at java.lang.Thread.run(java.base@17.0.2/Thread.java:833)
"Thread-1":
        at com.du.cpu.JstackDeadLockDemo.calLock_Obj2_First(JstackDeadLockDemo.java:49)
        - waiting to lock <0x0000000629237030> (a java.lang.Object)
        - locked <0x0000000629237040> (a java.lang.Object)
        at com.du.cpu.JstackDeadLockDemo.lambda$testDeadlock$1(JstackDeadLockDemo.java:23)
        at com.du.cpu.JstackDeadLockDemo$$Lambda$15/0x0000000800c01428.run(Unknown Source)
        at java.lang.Thread.run(java.base@17.0.2/Thread.java:833)

Found 1 deadlock.

jconsole

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值