多线程基础系列之 CountDownLatch

📒一、线程工具

背景故事

🔊 很久以前面试大厂,被面试官问到有没有使用过 CountDownLatch,我说使用过;面试官追问,那你可以说一下具体使用场景吗,脑袋一懵,竟然答不上来。是的,我背的八股文已经忘了,之前我也确实没有使用过。

最近碰到有一个同事错误地使用了 CountdownLatch,不由的想谈一谈 CountdownLatch 的使用。

官方解释

同步工具类,允许一个或多个线程一直等待,直到其他线程运行完成后再执行 (A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.)

单线程等待执行 多线程同步等待执行

有了上面理解,接下来再看看应用场景

📚二、应用场景

举几个实际应用用到的例子,不会使用 CountDownLatch 的请抄作业了。

单线程等

RPC 远程调用场景

  1. RPC 底层通信调用是一个异步行为。
  2. 在调用之前设置 CountDownLatch
  3. 异步调用结束后,回调 countDown 方法
  4. 这个时候主方法继续向下执行
Java 复制代码
// 1. 设置  CountDownLatch
final CountDownLatch latch = new CountDownLatch(1);
final RpcResult result = new RpcResult();

// 2.发起远程 RPC 调用。 RPC 返回结果, 触发 callback 调用,修改 CountDownLatch
remoteInvoke(getHost(requestLine), request, new CallBack(timeout) {
    @Override
    public void handled(Response response) throws Exception {
        try {
            Response.Status status = response.startLine();
            byte[] bytes = response.body().bytes();
            ......
            result.setStateCode(status.code());
        } catch (Exception e) {
            result.setCause(t);
        } finally {
            // 必须放在 final里面
            latch.countDown();
        }
    }
});

可以把 remoteInvoke 理解为线程操作。

很多框架的源码启动类,都会有异步加载过程并同步等待,就是下面这个模板代码,试着再你的工程中用一用。

Java 复制代码
  final CountDownLatch launchLatch = new CountDownLatch(1);
  Thread launcherThread = new Thread(() -> {
      try {
        .......
      } finally {
          launchLatch.countDown();
      }
  });
   .....
 latch.await(timeout, TimeUnit.MILLISECONDS);

多线程等

多线程等待的场景,比如并发下载,并发查询等等

Java 复制代码
final CountDownLatch latch = new CountDownLatch(nTasks);
for (int i = 0; i < nTasks; ++i) {
    executorService.submit(
            new Runnable() {
                @Override
                public void run() {
                    try {
                        // 业务操作 method
                    } finally {
                        latch.countDown();
                    } 
                }
            });
}
latch.await();

补充场景

  • 启动类,异步加载资源
  • 源码中的注释也有两个详细的例子

📑三、其他补充

源码浅析

内部实现一个 AbstractQueuedSynchronizer(AQS 队列同步器),源码并不多,主要,通过改变 private volatile int state 值来实现线程之间的协助。 state 不为 0 继续等待,为 0 向下执行。调用 countDown 则 state 减一

学会慢慢的把这些工具类应用到你的工程里面,别再做 CRUD boy 了。

同类工具

  1. Thread#join
  2. Future#get
  3. CompletableFuture

纸上得来终觉浅,绝知此事要躬行.

相关推荐
牛奔1 小时前
Go 如何避免频繁抢占?
开发语言·后端·golang
寻星探路5 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
想用offer打牌6 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
曹牧7 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
KYGALYX7 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
爬山算法8 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
kfyty7258 小时前
集成 spring-ai 2.x 实践中遇到的一些问题及解决方案
java·人工智能·spring-ai
猫头虎8 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven