多线程基础系列之 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

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

相关推荐
颜如玉16 分钟前
HikariCP:Dead code elimination优化
后端·性能优化·源码
考虑考虑1 小时前
Jpa使用union all
java·spring boot·后端
用户3721574261351 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
bobz9652 小时前
virtio vs vfio
后端
浮游本尊2 小时前
Java学习第22天 - 云原生与容器化
java
Rexi2 小时前
“Controller→Service→DAO”三层架构
后端
bobz9653 小时前
计算虚拟化的设计
后端
深圳蔓延科技3 小时前
Kafka的高性能之路
后端·kafka
Barcke3 小时前
深入浅出 Spring WebFlux:从核心原理到深度实战
后端
JuiceFS3 小时前
从 MLPerf Storage v2.0 看 AI 训练中的存储性能与扩展能力
运维·后端