单元测试中启动多线程需避免Thread.sleep(),应使用CountDownLatch或CyclicBarrier同步、ExecutorService配shutdown/awaitTermination清理、AtomicInteger等线程安全类型保护共享状态,并用@RepeatedTest和@Timeout提升并发问题暴露概率。

单测里启动多线程,Thread.sleep() 不可靠
Java 单元测试默认运行在单线程中,一旦你手动 new Thread() 或用 ExecutorService 启动并发逻辑,就面临“主线程提前结束、子线程还没跑完”的问题。很多人第一反应是加 Thread.sleep(1000) 等结果,但这是典型反模式:既不稳定(慢机器可能没睡够),又拖慢整个测试套件。
更稳妥的做法是用同步机制显式等待:
- 用
CountDownLatch:主线程await(),每个工作线程完成时countDown() - 用
CyclicBarrier:适合多个线程需在某点“齐步走”的场景(如并发初始化) - 避免在测试里依赖时间,除非你明确在测超时逻辑(此时应用
CompletableFuture.orTimeout()或Future.get(timeout, unit))
ExecutorService 必须显式 shutdown() 和 awaitTermination()
测试中常用 Executors.newFixedThreadPool(2) 模拟并发,但若不清理,线程池会持续持有非守护线程,导致 JUnit 进程无法退出——尤其在 Maven 多模块构建或 CI 环境下,可能卡住后续测试。
正确写法必须成对出现:
立即学习“Java免费学习笔记(深入)”;
ExecutorService executor = Executors.newFixedThreadPool(2);
try {
// 提交任务...
executor.submit(() -> doWork());
// 等待所有任务结束
executor.shutdown();
assertTrue(executor.awaitTermination(3, TimeUnit.SECONDS));
} finally {
if (!executor.isTerminated()) {
executor.shutdownNow(); // 强制终止残留任务
}
}
注意:awaitTermination() 返回 false 表示超时未结束,此时应调用 shutdownNow() 并检查是否真有死循环或阻塞 I/O。
共享状态被多个线程修改?用 AtomicInteger 或 ConcurrentHashMap 替代普通变量
常见错误:在测试里定义一个 int count = 0,然后多个线程都执行 count++,最后断言 count == 10 ——这几乎必然失败,因为 ++ 不是原子操作。
解决方式取决于测试目的:
- 如果只是验证并发逻辑的**正确性**(比如计数器最终值),直接用
AtomicInteger:它能保证可见性和原子性,且无需额外同步 - 如果模拟真实业务对象(如缓存、队列),优先用线程安全容器:
ConcurrentHashMap、CopyOnWriteArrayList,而非加synchronized块包装HashMap——后者易漏锁、难覆盖边界 - 慎用
volatile:它只保可见性,不保原子性,volatile int仍不能安全做++
JUnit 5 的 @RepeatedTest 和 @Timeout 是并发测试的加速器
并发 Bug 往往具有随机性(如竞态、丢失唤醒),单次运行很难复现。靠人工反复跑 mvn test 效率太低。
JUnit 5 提供两个关键能力:
-
@RepeatedTest(100):连续运行同一测试 100 次,显著提升暴露概率;注意每次调用都是干净实例,无需手动重置状态 -
@Timeout(value = 500, unit = TimeUnit.MILLISECONDS):给测试方法设硬性超时,防止因死锁、无限等待导致整个测试套件挂起 - 组合使用效果更好:比如
@RepeatedTest(50) @Timeout(200),既压测又防卡死
注意:@Timeout 对整个测试方法生效,不是对某个 Future.get() 单独设限;若需细粒度控制,仍得用 Future.get(200, MILLISECONDS)。
并发单测最难的不是写代码,而是设计可重复、可观测、可终止的测试场景。线程调度不可控,所以一切依赖“运气”的等待和断言都要替换为显式同步;资源不释放比逻辑出错更隐蔽,所以 ExecutorService 的生命周期管理必须像数据库连接一样严格。别让测试本身成为并发 bug 的温床。










