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

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

相关推荐
醉颜凉29 分钟前
【NOIP提高组】潜伏者
java·c语言·开发语言·c++·算法
阿维的博客日记33 分钟前
java八股-jvm入门-程序计数器,堆,元空间,虚拟机栈,本地方法栈,类加载器,双亲委派,类加载执行过程
java·jvm
qiyi.sky34 分钟前
JavaWeb——Web入门(8/9)- Tomcat:基本使用(下载与安装、目录结构介绍、启动与关闭、可能出现的问题及解决方案、总结)
java·前端·笔记·学习·tomcat
lapiii35837 分钟前
图论-代码随想录刷题记录[JAVA]
java·数据结构·算法·图论
RainbowSea40 分钟前
4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明
java·spring·spring cloud
程序员小明z41 分钟前
基于Java的药店管理系统
java·开发语言·spring boot·毕业设计·毕设
夜色呦1 小时前
现代电商解决方案:Spring Boot框架实践
数据库·spring boot·后端
爱敲代码的小冰1 小时前
spring boot 请求
java·spring boot·后端
Lyqfor1 小时前
云原生学习
java·分布式·学习·阿里云·云原生
程序猿麦小七2 小时前
今天给在家介绍一篇基于jsp的旅游网站设计与实现
java·源码·旅游·景区·酒店