导读:本期聚焦于小伙伴创作的《如何使用jstack工具排查Java环境的死锁与CPU飙升问题》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何使用jstack工具排查Java环境的死锁与CPU飙升问题》有用,将其分享出去将是对创作者最好的鼓励。

jstack是JDK内置的命令行工具,主要用于生成Java虚拟机当前时刻的线程快照,通过线程快照可以查看每个线程的执行状态、持有的锁信息以及调用栈路径,是排查Java应用线程相关问题的常用工具。

如何使用jstack工具排查Java环境的死锁与CPU飙升问题

jstack工具基本使用

使用jstack前需要先获取目标Java进程的PID,可以通过jps命令快速查看当前运行的Java进程列表,命令如下:

# 查看所有Java进程PID和主类名
jps -l

获取到PID后,执行jstack命令导出线程快照,基础用法为:

# 导出线程快照到指定文件
jstack 进程PID > jstack_log.txt

如果需要查看更详细的锁信息,可以添加-l参数:

jstack -l 进程PID > jstack_detail_log.txt

使用jstack排查Java死锁问题

死锁是指两个或多个线程互相持有对方需要的锁,导致所有线程都无法继续执行的情况。jstack输出的日志中会自动检测并标记死锁信息,排查步骤如下:

步骤1:触发死锁场景

以下是一个简单的死锁示例代码,两个线程互相持有对方需要的锁:

public class DeadLockDemo {
    private static final Object LOCK_A = new Object();
    private static final Object LOCK_B = new Object();

    public static void main(String[] args) {
        // 线程1先获取LOCK_A,再尝试获取LOCK_B
        new Thread(() -> {
            synchronized (LOCK_A) {
                System.out.println("线程1获取到LOCK_A");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (LOCK_B) {
                    System.out.println("线程1获取到LOCK_B");
                }
            }
        }, "Thread-1").start();

        // 线程2先获取LOCK_B,再尝试获取LOCK_A
        new Thread(() -> {
            synchronized (LOCK_B) {
                System.out.println("线程2获取到LOCK_B");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (LOCK_A) {
                    System.out.println("线程2获取到LOCK_A");
                }
            }
        }, "Thread-2").start();
    }
}

步骤2:导出线程快照分析

运行上述代码后,通过jps获取进程PID,执行jstack导出日志,在日志末尾会自动出现死锁提示:

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

Java stack information for the threads listed above:
===================================================
"Thread-2":
	at DeadLockDemo.lambda$main$1(DeadLockDemo.java:30)
	- waiting to lock <0x000000076abf8c98> (a java.lang.Object)
	- locked <0x000000076abf8ca8> (a java.lang.Object)
"Thread-1":
	at DeadLockDemo.lambda$main$0(DeadLockDemo.java:16)
	- waiting to lock <0x000000076abf8ca8> (a java.lang.Object)
	- locked <0x000000076abf8c98> (a java.lang.Object)

Found 1 deadlock.

从日志中可以明确看到两个线程的等待锁和持有锁信息,以及死锁发生的具体代码行,直接定位到对应的代码逻辑修改即可解决死锁问题。

使用jstack排查CPU飙升问题

当Java应用CPU占用过高时,通常是有线程在执行大量计算或者死循环逻辑,排查步骤如下:

步骤1:定位高CPU占用的线程

首先通过top命令查看进程的资源占用情况,找到CPU占用高的Java进程PID,然后执行以下命令查看该进程下所有线程的CPU占用:

# 查看进程下线程CPU占用,按CPU排序
top -Hp 进程PID

记录下CPU占用最高的线程ID,将线程ID转换为16进制,因为jstack日志中的线程ID是16进制格式:

# 将10进制线程ID转为16进制,比如线程ID是12345,执行以下命令
printf "%xn" 12345

步骤2:在jstack日志中定位线程

导出jstack日志后,搜索转换后的16进制线程ID,找到对应的线程信息,查看线程的调用栈:

"HighCpuThread" #12 prio=5 os_prio=0 tid=0x00007f8a48013800 nid=0x3039 runnable [0x00007f8a3c5f7000]
   java.lang.Thread.State: RUNNABLE
	at CpuHighDemo.calculate(CpuHighDemo.java:15)
	at CpuHighDemo.lambda$main$0(CpuHighDemo.java:8)
	at CpuHighDemo$$Lambda$1/0x0000000800b91440.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)

根据调用栈中的代码行,定位到具体的业务逻辑,比如是否存在死循环、大量重复计算等问题,针对性优化即可。

jstack使用注意事项

  • jstack需要和目标Java进程的用户权限一致,否则可能无法导出快照
  • 频繁执行jstack可能会对应用性能产生轻微影响,建议在问题复现时按需执行
  • 如果应用使用了线程池,需要注意线程的命名,方便快速定位业务线程
  • 对于容器化部署的Java应用,需要在容器内部执行jstack命令,或者挂载宿主机的JDK路径使用

jstackJava死锁排查CPU飙升排查JVM工具修改时间:2026-06-11 17:21:38

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。