java.util.concurrent public class CountDownLatch
extends Object
一种同步辅助,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。
CountDownLatch使用给定的计数进行初始化。由于调用了countDown方法, await方法一直阻塞,直到当前计数达到零,之后所有等待的线程都被释放,任何后续的await调用立即返回。这是一次性现象——计数无法重置。如果您需要重置计数的版本,请考虑使用CyclicBarrier 。
CountDownLatch是一种多功能同步工具,可用于多种用途。使用计数 1 初始化的CountDownLatch用作简单的开/关锁存器或门:所有调用await的线程在门处等待,直到它被调用countDown的线程打开。初始化为N的CountDownLatch可用于使一个线程等待,直到N个线程完成某个动作,或者某个动作已完成 N 次。
CountDownLatch的一个有用属性是它不需要调用countDown的线程在继续之前等待计数达到零,它只是阻止任何线程继续await ,直到所有线程都可以通过。
示例用法:这是一对类,其中一组工作线程使用两个倒计时锁存器:
第一个是启动信号,它阻止任何工人继续前进,直到司机准备好让他们继续前进;
第二个是完成信号,允许驱动程序等待所有工作人员完成。
| class Driver { |
| void main() throws InterruptedException { |
| CountDownLatch startSignal = new CountDownLatch(1); |
| CountDownLatch doneSignal = new CountDownLatch(N); |
| |
| for (int i = 0; i < N; ++i) |
| new Thread(new Worker(startSignal, doneSignal)).start(); |
| |
| doSomethingElse(); |
| startSignal.countDown(); |
| doSomethingElse(); |
| doneSignal.await(); |
| } |
| } |
| class Worker implements Runnable { |
| private final CountDownLatch startSignal; |
| private final CountDownLatch doneSignal; |
| Worker(CountDownLatch startSignal, CountDownLatch doneSignal) { |
| this.startSignal = startSignal; |
| this.doneSignal = doneSignal; |
| } |
| public void run() { |
| try { |
| startSignal.await(); |
| doWork(); |
| doneSignal.countDown(); |
| } catch (InterruptedException ex) {} |
| } |
| |
| void doWork() { ... } |
| } |
另一个典型的用法是将一个问题分成 N 个部分,用一个 Runnable 描述每个部分,该 Runnable 执行该部分并在锁存器上倒计时,并将所有 Runnables 排队到一个 Executor。当所有子部分都完成后,协调线程就可以通过await了。 (当线程必须以这种方式重复倒计时时,请改用CyclicBarrier 。)
| class Driver2 { |
| void main() throws InterruptedException { |
| CountDownLatch doneSignal = new CountDownLatch(N); |
| Executor e = ... |
| |
| for (int i = 0; i < N; ++i) |
| e.execute(new WorkerRunnable(doneSignal, i)); |
| |
| doneSignal.await(); |
| } |
| } |
| class WorkerRunnable implements Runnable { |
| private final CountDownLatch doneSignal; |
| private final int i; |
| WorkerRunnable(CountDownLatch doneSignal, int i) { |
| this.doneSignal = doneSignal; |
| this.i = i; |
| } |
| public void run() { |
| try { |
| doWork(i); |
| doneSignal.countDown(); |
| } catch (InterruptedException ex) {} |
| } |
| |
| void doWork() { ... } |
| } |
内存一致性影响:在计数达到零之前,线程中的操作在调用countDown()之前发生在从另一个线程中的相应await()成功返回之后的操作。
关注我的公众号SpaceObj 领取idea系列激活码

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)