发布于2026-07-08 阅读(0)
扫一扫,手机访问
在并发调试的战场上,ReentrantLock 其实是个挺让人头疼的家伙——你没办法像 synchronized 那样,光靠看一眼线程 dump 就能把锁的持有者和等待队列看得清清楚楚。不过别急着挠头,有两个被不少人忽略的实用工具——getQueuedThreads() 和 getHoldCount(),能帮你快速定位死锁、锁泄漏,甚至是那些莫名其妙的重入异常。

先说说这俩工具分别能干什么。
getQueuedThreads() 返回一个列表,里面按 FIFO 顺序排着所有已经调用了 lock()、但还没拿到锁的线程(也就是那些被困在 AQS 同步队列里的倒霉蛋)。注意,它不包含因为 Condition.await() 而挂起的线程。怎么用?几个关键点:
Thread.getName() 和 Thread.getState(),可以判断线程是不是卡在了 BLOCKED 状态。getHoldCount() 是一个实例方法,必须由持有该锁的线程调用才有效——它返回当前线程对该锁的重入次数。如果线程没持有锁,就返回 0。这个值很关键:
lock() 调用,极可能导致 unlock() 不匹配。isHeldByCurrentThread() 一起用,能构建更健壮的断言,比如 assert lock.isHeldByCurrentThread() && lock.getHoldCount() == 1;,双重确认,心里踏实。单看一个方法信息有限,把两者结合起来分析才能揭示真实状况:
getQueuedThreads() 中持续出现,并且它的堆栈显示正在等待另一个 ReentrantLock,那就同时检查一下它自己持有的锁(通过 getHoldCount() > 0 判断)是否也被别人排队等着。双管齐下,死锁几乎无所遁形。getQueuedThreads().size() 持续增长,但活跃线程数保持稳定——多半是有 lock() 之后忘了 unlock(),尤其是在异常分支里。getHoldCount() 达到 5 次以上,而且没有明显的递归逻辑——那就赶紧检查一下,是不是在循环或者监听器里反复调用 lock() 了。别等到线上出故障了才临时抱佛脚去加日志。这里更推荐一种轻量化的接入方式:
lock.getQueueLength()(它返回等待线程数量,比 getQueuedThreads() 开销小)作为 Micrometer 指标,定时上报,随时掌握全局排队情况。withLock(Runnable))里,打开 debug 日志时自动记录 getHoldCount() 和排队长度。这样既不会影响生产性能,排查时又能拿到一手信息。-Djdk.locks.friendly=true,可以增强 jstack 对 ReentrantLock 的识别能力,让线程 dump 里出现“waiting for lock”这样更清晰易懂的提示。上一篇:如何在 Java 中通过 反射创建数组对象 实现对异构数据结构的动态容器封装
下一篇:GenericSignatureFormatError 混淆修复:分析在 Android 开发中 R8 工具处理异常变量签名时的常见 Bug
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8