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

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

相关推荐
绝无仅有几秒前
猿辅导MySQL面试常见问题解析(一)
后端·面试·github
云泽8082 小时前
函数模板与类模板:C++泛型编程核心解析
java·开发语言·c++
缺点内向5 小时前
Java:创建、读取或更新 Excel 文档
java·excel
带刺的坐椅6 小时前
Solon v3.4.7, v3.5.6, v3.6.1 发布(国产优秀应用开发框架)
java·spring·solon
四谎真好看7 小时前
Java 黑马程序员学习笔记(进阶篇18)
java·笔记·学习·学习笔记
桦说编程7 小时前
深入解析CompletableFuture源码实现(2)———双源输入
java·后端·源码
java_t_t7 小时前
ZIP工具类
java·zip
舒一笑8 小时前
大模型时代的程序员成长悖论:如何在AI辅助下不失去竞争力
后端·程序员·掘金技术征文
lang201509288 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
小羊在睡觉9 小时前
golang定时器
开发语言·后端·golang