✅ 线程安全——CountDownLatch的countDown()基于CAS原子更新state,10线程各调用10次共100次后await不超时,证明减操作无丢失、无竞争,无需外部同步。

直接用一段 10 行以内的代码,启动多个线程并发调用 countDown(),再检查最终计数是否精确归零——如果每次都能成功 await,就证明它内部的减操作是原子且线程安全的。
核心验证思路
CountDownLatch 的线程安全性不靠用户加锁,而靠其内部使用 Unsafe.compareAndSetInt(或 AQS 的 state 原子更新)实现。我们不需要看源码,只需设计一个“竞态放大”场景:
- 初始化 CountDownLatch(100)
- 开 10 个线程,每线程执行 10 次
countDown() - 主线程调用
await(),并设超时(比如 1 秒) - 若 await 不超时返回,说明 100 次 countDown 全部生效、无丢失、无重复——即减操作是原子的
可直接运行的极简验证代码
(Java,无需依赖,JDK 8+)
CountDownLatch latch = new CountDownLatch(100);
List<Thread> ts = new ArrayList<>();
for (int i = 0; i < 10; i++) {
ts.add(new Thread(() -> { for (int j = 0; j < 10; j++) latch.countDown(); }));
}
ts.forEach(Thread::start);
ts.forEach(t -> { try { t.join(); } catch (InterruptedException e) {} });
System.out.println(latch.await(1, TimeUnit.SECONDS) ? "✅ 线程安全" : "❌ 计数异常");
为什么这个验证够“实战”又够“极简”
它绕过所有封装和业务逻辑,直击本质:
- 没用 ExecutorService —— 避免线程池复用带来的干扰
- 没加日志或 sleep —— 消除时序掩盖问题的可能
- 用 join 等待全部线程结束再 await —— 确保所有 countDown 已发起
- 超时判断替代“打印 getCount()” —— 因为 getCount() 非原子快照,不能作为判据
补充说明:不是“看起来安全”,而是“必然安全”
如果你把 countDown() 替换成 sharedVar--(int 共享变量),同样 10×10 场景,大概率输出 false;但 CountDownLatch 不会。这不是巧合,是 JDK 实现强制保证:countDown() 是一个不可分割的 CAS 减操作,失败会重试,对调用者完全透明。所以你永远不需要在外层再加 synchronized 或 Lock。

















