CountDownLatch 误用在于等线程结束而非任务完成,须确保每个任务在 finally 中调用 countDown();CyclicBarrier 的 barrierAction 由最后到达线程执行,应轻量且避免异常;两者均需超时控制,不可无参 await()。

CountDownLatch 用错场景:等线程结束 ≠ 等任务完成
很多人把 CountDownLatch 当作“等所有线程跑完再继续”的万能锁,结果发现主线程提前醒了。根本原因是:它只数 countDown() 调用次数,不关心调用者是不是目标线程,也不校验任务是否真执行完了。
典型误用:ExecutorService 提交任务后,立刻在主线程调用 latch.await(),但没确保每个任务内部都调用了 latch.countDown() —— 比如某个任务抛异常退出,漏掉 countDown(),主线程就永久阻塞。
- 必须保证每个参与线程(或每个任务)在逻辑完成点(无论成功/失败)都执行一次
countDown() - 推荐在
finally块里调用countDown(),避免异常跳过 -
CountDownLatch是一次性用品:await()返回后,再次调用不会阻塞;若需重复使用,选CyclicBarrier
CyclicBarrier 的 barrierAction 容易被忽略的执行时机
CyclicBarrier 的构造函数可传入一个 Runnable barrierAction,但它不是“所有线程到达后立即执行”,而是由**最后一个到达的线程**负责执行——这意味着:如果这个线程后续还要做耗时操作,会拖慢整个栅栏释放;如果它抛异常,BrokenBarrierException 会传播给所有等待线程。
常见陷阱是把日志、统计、资源初始化等逻辑直接塞进 barrierAction,导致某次循环卡顿,进而引发下游超时。
立即学习“Java免费学习笔记(深入)”;
-
barrierAction应尽量轻量,避免 I/O、锁竞争、复杂计算 - 若需异步处理,应在
barrierAction中提交到独立线程池,而非同步等待 - 注意:
barrierAction执行失败(抛出非RuntimeException)会导致栅栏进入破损状态,后续await()直接抛BrokenBarrierException
CountDownLatch 和 CyclicBarrier 的线程安全边界不同
两者都线程安全,但“安全”的范围不同:CountDownLatch 的 countDown() 和 await() 可由任意线程调用;而 CyclicBarrier 的 await() 必须由参与方线程调用,且每个线程只能调用一次 per cycle(即每轮等待),否则会抛 IllegalMonitorStateException 或触发破损。
本程序源码为asp与acc编写,并没有花哨的界面与繁琐的功能,维护简单方便,只要你有一些点点asp的基础,二次开发易如反掌。 1.功能包括产品,新闻,留言簿,招聘,下载,...是大部分中小型的企业建站的首选。本程序是免费开源,只为大家学习之用。如果用于商业,版权问题概不负责。1.采用asp+access更加适合中小企业的网站模式。 2.网站页面div+css兼容目前所有主流浏览器,ie6+,Ch
更隐蔽的问题是重用:多个线程反复调用同一个 CyclicBarrier 实例时,若某线程因中断/超时退出,未重置栅栏,后续调用可能直接失败。
- 不要在
CyclicBarrier的await()外部手动调用reset()—— 它会强行唤醒所有等待线程并清空计数,导致状态混乱 - 若需强制恢复,应捕获
BrokenBarrierException后新建实例,而非复用旧的 -
CountDownLatch没有reset()方法,这是设计使然:它表达的是“事件发生”语义,不是循环协作
性能与调试:await() 超时设置不是可选项
生产环境几乎从不写无参 await()。没有超时的 CountDownLatch.await() 或 CyclicBarrier.await() 一旦卡住,只能靠线程 dump 排查,且无法自动恢复。
超时值也不能拍脑袋定:设太短,正常波动就失败;设太长,故障响应延迟高。建议结合任务 SLA 和上游超时倒推。
- 务必使用带超时的重载方法:
latch.await(30, TimeUnit.SECONDS)、barrier.await(10, TimeUnit.SECONDS) - 超时后要区分处理:
false(CountDownLatch)或TimeoutException(CyclicBarrier)意味着协作失败,需清理资源、记录告警,而不是重试 - JVM 级别线程 dump 中,阻塞在
sun.misc.Unsafe.park且堆栈含CountDownLatch$Sync或CyclicBarrier$Generation,基本可定位为未触发的倒计时或栅栏
真正难的不是 API 调用,而是厘清“谁该减一”“谁该等几轮”“失败后状态怎么收”。这两个类都不容许模糊语义——计数少一次,或漏等一轮,系统行为就不可预测。










