在Java里并发编程中的死锁如何检测_Java死锁监控与排查方法解析

秋瑶小哥_7363

秋瑶小哥_7363

2026-02-07

775人浏览

原创

java死锁能被自动检测,但仅限于synchronized内置锁场景;jvm通过threadmxbean可检测此类死锁,却无法识别reentrantlock等显式锁及wait/notify逻辑死锁。

在java里并发编程中的死锁如何检测_java死锁监控与排查方法解析

Java死锁能被自动检测吗?能,但仅限于线程持有对象监视器锁(synchronized)的场景

Java 虚拟机本身不主动预防死锁,但在运行时可通过 ThreadMXBean 检测到部分死锁——前提是这些死锁涉及的是内置锁(即 synchronized 块/方法持有的 java.lang.Object 监视器锁)。JVM 无法检测基于 java.util.concurrent.locks.Lock(如 ReentrantLock)的死锁,除非你显式调用其 getHoldCount() 或启用 fairness + 配合外部监控。

常见错误现象:jstack -l <pid></pid> 输出中出现 Found 1 deadlock.,但线上服务已卡住数分钟才被发现;或使用 VisualVM 查看线程状态时,多个线程长期处于 BLOCKED 状态,且堆栈显示互相等待对方持有的 monitor。

  • 检测触发条件:至少两个线程,每个都持有一个锁并试图获取另一个线程持有的锁
  • ThreadMXBean.findDeadlockedThreads() 返回非 null 数组即表示存在 synchronized 死锁
  • 该 API 不扫描 Lock 实现,也不覆盖 wait()/notify() 引发的逻辑死锁(例如线程 A wait() 在 obj1,线程 B wait() 在 obj2,双方都不 notify())

如何用 ThreadMXBean 主动轮询检测 synchronized 死锁

适合嵌入监控 Agent 或健康检查端点。注意不要高频调用(建议间隔 ≥30 秒),否则可能因锁竞争影响性能。

chartjs-reporter
chartjs-reporter

此技能用于在用户需要将结构化数据(查询结果、CSV 摘要、JSON 记录或 Python 字典/列表)转换为独立的 HTML 页面时使用。

下载
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long[] deadlockedIds = bean.findDeadlockedThreads(); // 返回 null 表示无死锁
if (deadlockedIds != null) {
    ThreadInfo[] infos = bean.getThreadInfo(deadlockedIds, true, true);
    for (ThreadInfo info : infos) {
        System.out.println("Deadlocked thread: " + info.getThreadName());
        System.out.println("Locked on: " + info.getLockName());
        System.out.println("Blocked by: " + info.getLockOwnerName());
    }
}
  • 第二个参数 true 表示采集线程堆栈,第三个 true 表示采集锁信息(包括持有者和等待者)
  • 若返回 deadlockedIds 长度为 0,不代表绝对安全——可能是死锁尚未形成,或只涉及 Lock 类型
  • 在容器化环境(如 Kubernetes)中,可将此逻辑封装为 /actuator/health 子项,配合 Prometheus 抓取

jstack 和 jcmd 哪个更适合线上紧急排查?优先用 jcmd

jstack 在某些 JDK 版本(尤其是旧版 HotSpot)下会尝试对目标 JVM 全局 safepoint,导致应用暂停(STW),而 jcmd 更轻量、更可靠。

  • 执行 jcmd <pid> VM.native_memory summary</pid> 可辅助判断是否因锁竞争引发内存分配阻塞
  • 真正查死锁用:jcmd <pid> Thread.print</pid> —— 输出等价于 jstack -l,但不会强制全局 safepoint
  • 如果进程已无响应,jstack -F <pid></pid> 可强制 attach,但风险更高;jcmd 无 -F 模式,失败即退出,更安全
  • 注意:所有命令需以与 Java 进程**相同用户**运行,否则权限拒绝(常见于容器内 root 启动但 jcmd 用非 root 执行)

ReentrantLock 死锁为什么 jstack 看不出来?因为锁信息不在 JVM 线程状态机里

ReentrantLock 是纯 Java 实现,其持有关系、等待队列都维护在 Lock 对象内部(比如 AbstractQueuedSynchronizer 的 CLH queue),JVM 线程状态仍显示为 WAITING 或 TIMED_WAITING,而非 BLOCKED。jstack 不解析 AQS 结构,所以无法标记“此线程在等 lockA,而 lockA 被线程X持有”。

  • 解决方案一:启用 ReentrantLock 的公平模式(new ReentrantLock(true)),虽不能检测死锁,但能避免饥饿,让问题更快暴露
  • 解决方案二:使用 lock.tryLock(timeout, unit) 替代 lock.lock(),超时后记录上下文并抛出业务异常,便于日志追踪
  • 解决方案三:借助字节码插桩(如 ByteBuddy)或代理,在每次 lock()/unlock() 时记录线程 ID 与锁实例哈希,构建运行时锁依赖图(较重,仅调试期启用)

真正棘手的从来不是“能不能检测”,而是“检测到了,但现场已过去十几秒,堆栈里看不出谁先拿了哪把锁”。所以关键不在事后分析,而在设计阶段就规避嵌套锁、统一加锁顺序、用 try-with-resources 配合 Lock 的 newCondition() 做细粒度等待——这些比任何监控都管用。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关专题

更多
python中print函数的用法
python中print函数的用法

python中print函数的语法是“print(value1, value2, ..., sep=' ', end='\n', file=sys.stdout, flush=False)”。本专题为大家提供print相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.27

2980

5

python print用法与作用
python print用法与作用

本专题整合了python print的用法、作用、函数功能相关内容,阅读专题下面的文章了解更多详细教程。

2026.02.03

249

24

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

2023.09.22

549

3

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

2024.03.01

1698

6

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

6007

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2548

6

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

6007

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2548

6

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

4298

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习