reentrantlock 无内置死锁检测机制,但可通过 threadmxbean 的 finddeadlockedthreads() 方法检测其引发的死锁;该方法返回死锁线程 id,结合 getthreadinfo() 和 getlockedsynchronizers() 可获取锁持有与等待详情,属快照式诊断,预防仍需依赖锁顺序、trylock 超时等策略。

ReentrantLock 本身不提供直接检测死锁的机制,Java 也没有内置 API 让 ReentrantLock 主动“报告”自己是否陷入死锁。死锁是多个线程互相等待对方持有的锁(不限于 ReentrantLock,也包括 synchronized),而 JVM 的死锁检测能力仅覆盖 所有可被 ThreadMXBean 监控的显式锁,其中就包含 ReentrantLock —— 但前提是这些锁由 java.util.concurrent.locks.LockSupport 或 AbstractOwnableSynchronizer 管理,且已注册到 JVM 的锁监控系统中(ReentrantLock 默认满足)。
利用 ThreadMXBean 检测 ReentrantLock 引发的死锁
JVM 提供了 ThreadMXBean 接口,可通过 ManagementFactory.getThreadMXBean() 获取实例,调用其 findDeadlockedThreads() 方法来识别处于死锁状态的线程。该方法能发现涉及 ReentrantLock、synchronized 和其他可监控锁的循环等待链。
- 必须确保 ReentrantLock 是通过标准方式创建(如 new ReentrantLock()),未禁用 AQS 的 owner tracking(默认开启)
- 调用 findDeadlockedThreads() 返回的是死锁线程 ID 数组,需进一步用 getThreadInfo(long[]) 获取详细堆栈和锁持有/等待信息
- 该检测是快照式、非实时的,适合诊断或定时巡检,不能用于实时预防
从 ThreadInfo 中提取 ReentrantLock 相关锁信息
获取到死锁线程后,可通过 ThreadInfo#getLockedSynchronizers() 获得当前线程持有的所有可监控锁(包括 ReentrantLock 实例),通过 ThreadInfo#getLockInfo() 和 getLockedMonitors() 区分 monitor 锁与 JUC 锁。
- getLockedSynchronizers() 返回 LockInfo[],每个 LockInfo 包含类名(如 "java.util.concurrent.locks.ReentrantLock$NonfairSync")和 identityHashCode,可用于定位具体锁实例
- 结合 getThreadInfo(ids, true, true) 启用堆栈和锁信息,能看清哪个线程在 await()、lock() 或 tryLock() 处阻塞,以及它正在等待哪个锁
- 注意:LockInfo 不包含锁的公平性、重入次数等细节,仅作识别用途
主动规避死锁比事后检测更有效
依赖 ThreadMXBean 检测属于被动诊断,无法防止死锁发生。对 ReentrantLock 使用,应优先采用预防策略:
- 按全局一致顺序获取多个锁(例如总是先 lock(lockA),再 lock(lockB))
- 使用 tryLock(timeout, unit) 设置超时,失败时释放已获锁并重试或回退
- 避免在持有一个 ReentrantLock 时调用未知外部代码(如回调、Stream.forEach),以防隐式获取其他锁
- 慎用 lockInterruptibly() 配合中断响应,配合超时形成双重保护
简单示例:触发并检测一个 ReentrantLock 死锁
以下代码构造两个线程,各自持有一把锁并尝试获取对方的锁:
(注:仅用于演示,生产环境勿照搬)运行后调用 ThreadMXBean.findDeadlockedThreads() 可返回两个线程 ID;再用 getThreadInfo 获取详情,会看到它们分别在 ReentrantLock.lock() 中 BLOCKED,并显示 waiting to lock —— 这个地址对应另一个线程持有的 ReentrantLock.sync 对象。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











