java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java jstack排查死锁

Java使用jstack排查死锁(面试考点)

作者:砍材农夫

jstack 是 JDK 自带的命令行工具,用于生成 Java 进程的线程快照,通过分析线程快照,可以快速定位死锁问题,下面就来详细的介绍一下,感兴趣的可以了解一下

jstack 是 JDK 自带的命令行工具,用于生成 Java 进程的线程快照(thread dump)。通过分析线程快照,可以快速定位死锁问题。

1. 获取 Java 进程 ID

首先,找到目标 Java 进程的 PID(进程 ID)。使用 jps 命令:

jps -l

输出示例:

12345 com.example.MyApplication
67890 sun.tools.jps.Jps

记录下应用进程的 PID,例如 12345

2. 生成线程快照

使用 jstack 命令生成线程快照:

jstack <pid> > thread_dump.txt

例如:

jstack 12345 > thread_dump.txt

如果应用因死锁导致无响应,可以添加 -l 选项(显示锁信息):

jstack -l 12345 > thread_dump.txt

注意:在某些环境下(如容器),可能需要使用 sudo 或以应用运行用户身份执行。

3. 分析线程快照

打开生成的 thread_dump.txt,查找死锁信息。

3.1 查找死锁摘要

jstack 会在线程快照末尾自动检测并输出死锁摘要,类似:

Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f8b5c00a5a8 (object 0x00000000d5f6e3a0, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f8b5c00b0b0 (object 0x00000000d5f6e3b0, a java.lang.Object),
  which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
        at com.example.DeadlockExample.method2(DeadlockExample.java:25)
        - waiting to lock <0x00000000d5f6e3a0> (a java.lang.Object)
        - locked <0x00000000d5f6e3b0> (a java.lang.Object)
        at com.example.DeadlockExample.run(DeadlockExample.java:15)
"Thread-0":
        at com.example.DeadlockExample.method1(DeadlockExample.java:18)
        - waiting to lock <0x00000000d5f6e3b0> (a java.lang.Object)
        - locked <0x00000000d5f6e3a0> (a java.lang.Object)
        at com.example.DeadlockExample.run(DeadlockExample.java:10)

3.2 手动分析线程堆栈

如果没有自动摘要(例如使用 jstack 的旧版本),可以手动查找以下特征:

找出相互等待锁的线程对,即线程 A 持有锁 L1 等待锁 L2,线程 B 持有锁 L2 等待锁 L1。

4. 解读死锁信息

从摘要中可以获取:

5. 解决死锁

根据堆栈定位到代码,常见解决方式:

6. 完整示例

以下是一个简单的死锁代码及使用 jstack 排查的演示。

6.1 死锁代码

public class DeadlockExample implements Runnable {
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();
    @Override
    public void run() {
        if (Thread.currentThread().getName().equals("Thread-0")) {
            method1();
        } else {
            method2();
        }
    }
    private void method1() {
        synchronized (lock1) {
            System.out.println("Thread-0 持有 lock1");
            try { Thread.sleep(100); } catch (InterruptedException e) {}
            synchronized (lock2) {
                System.out.println("Thread-0 持有 lock2");
            }
        }
    }
    private void method2() {
        synchronized (lock2) {
            System.out.println("Thread-1 持有 lock2");
            try { Thread.sleep(100); } catch (InterruptedException e) {}
            synchronized (lock1) {
                System.out.println("Thread-1 持有 lock1");
            }
        }
    }
    public static void main(String[] args) {
        DeadlockExample example = new DeadlockExample();
        Thread t1 = new Thread(example, "Thread-0");
        Thread t2 = new Thread(example, "Thread-1");
        t1.start();
        t2.start();
    }
}

6.2 使用 jstack 排查

# 1. 找到 PID
jps -l
# 2. 生成快照
jstack -l 12345 > deadlock.txt
# 3. 查看死锁摘要
grep -A 20 "Found one Java-level deadlock" deadlock.txt

输出类似:

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

7. 注意事项

通过以上步骤,可以快速定位并解决 Java 应用中的死锁问题。

到此这篇关于Java使用jstack排查死锁(面试考点)的文章就介绍到这了,更多相关Java jstack排查死锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文