ReentrantLock并发测试需验证互斥性(多线程竞争下sharedCounter结果准确)、可重入性(同线程多次lock/unlock且getHoldCount递增)、异常安全(finally解锁)及死锁规避(锁顺序一致、tryLock超时),辅以队列长度和线程堆栈观测。

测试 ReentrantLock 在多线程并发下的正确性,核心是验证它是否真正实现了「互斥」和「可重入」,同时不出现死锁、丢失锁、重复释放等行为。不能只靠“跑起来没报错”来判断,得设计有针对性的并发场景并观察关键指标。
构造高竞争场景,验证互斥性
让多个线程反复尝试获取同一把锁,并在临界区内修改共享变量(如计数器),最后检查结果是否符合串行预期。
- 用
CountDownLatch控制所有线程同时启动,增大竞争概率 - 临界区做简单但不可拆分的操作,例如
sharedCounter++(注意:这里必须加锁保护,否则本身就不安全) - 线程数设为 CPU 核心数的 2–5 倍,运行足够多次(如 10_000 次/线程)
- 最终
sharedCounter必须等于总操作次数,否则说明有竞态——锁没起作用
验证可重入性:同一线程多次 lock/unlock
写一个递归或嵌套调用的方法,在持有锁的情况下再次调用 lock.lock(),然后配对调用 unlock() 多次,确认不会抛出异常且能正常退出。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 典型测试:在一个
lock()后调用另一个也需该锁的方法,看是否阻塞(不应阻塞) - 检查
getHoldCount()返回值是否随嵌套深度递增,isHeldByCurrentThread()是否始终为true - 确保最终调用
unlock()次数等于lock()次数,否则会抛IllegalMonitorStateException
检测异常路径下的锁泄漏与死锁风险
真实业务中临界区可能抛异常,要验证锁是否仍能被释放;也要避免因锁顺序不当导致死锁。
- 在
try块中加锁,finally中解锁——这是强制要求,测试时故意在临界区 throw Exception,确认锁仍被释放(可用isLocked()辅助断言) - 模拟两个线程按不同顺序获取两把锁(如线程 A:lock1 → lock2;线程 B:lock2 → lock1),运行多次并设置超时,观察是否卡住(可用
ThreadMXBean.findDeadlockedThreads()检测) - 使用
tryLock(long, TimeUnit)配合超时,验证未获取到锁时能否及时失败而非无限等待
借助工具辅助观测与断言
光靠结果值不够,还需观察锁的运行时状态。
- 用
getQueueLength()和hasQueuedThreads()判断是否有线程在等待,配合日志确认排队行为符合预期 - JVM 自带
jstack或 JConsole 查看线程堆栈,确认阻塞线程确实停在AbstractQueuedSynchronizer$ConditionObject.await()或类似位置 - 单元测试中避免
Thread.sleep()等不确定等待,改用CountDownLatch或CyclicBarrier同步控制点
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










