0

0

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

P粉602998670

P粉602998670

发布时间:2026-02-07 02:13:36

|

735人浏览过

|

来源于php中文网

原创

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 输出中出现 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 秒),否则可能因锁竞争影响性能。

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 更轻量、更可靠。

Stylized
Stylized

AI产品图背景替换

下载

立即学习Java免费学习笔记(深入)”;

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

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

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

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

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

相关文章

编程速学教程(入门课程)
编程速学教程(入门课程)

编程怎么学习?编程怎么入门?编程在哪学?编程怎么学才快?不用担心,这里为大家提供了编程速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

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

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

191

2023.09.27

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

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

4

2026.02.03

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

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

240

2023.09.22

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

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

600

2024.03.01

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

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

403

2023.07.18

堆和栈区别
堆和栈区别

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

582

2023.08.10

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

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

403

2023.07.18

堆和栈区别
堆和栈区别

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

582

2023.08.10

Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

2

2026.02.06

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3.3万人学习

C# 教程
C# 教程

共94课时 | 8.7万人学习

Java 教程
Java 教程

共578课时 | 59万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号