zoukankan      html  css  js  c++  java
  • 并发编程学习笔记(十九、CountDownLatch源码分析)

    目录:

    • CountDownLatch是什么
    • 为什么要有CountDownLatch
    • CountDownLatch源码分析

    CountDownLatch是什么

    CountDownLatch是一种闭锁,也叫倒数计数器,它可以等待多个线程执行完毕后再执行某一件事情。

    比如你app的首页要加载很多个模块,而这些模块又处于不同服务,这时候你就可以开启多个线程去分别调用这些模块;然后你后续的一个操作需要用到刚刚调用的那些服务返回的数据,这时候你就可以用CountDownLatch了。

    为什么要有CountDownLatch

    针对上面那个问题你可能会说,那直接用Thread.join()不就可以了嘛。当然就简单的场景来说,join()的确就够用了,而CountDownLatch其实也就是对join()的一种扩展,它可以适用于更复杂的场景。

    我们通过一段代码来看看为何CountDownLatch的控制粒度更细(为了方便我把两个demo的代码写一块了)。

     1 public class ThreadA extends Thread {
     2 
     3     private CountDownLatch countDownLatch;
     4 
     5     public ThreadA() {
     6     }
     7 
     8     public ThreadA(CountDownLatch countDownLatch) {
     9         this.countDownLatch = countDownLatch;
    10     }
    11 
    12     @Override
    13     public void run() {
    14         System.out.println("threadA start...");
    15 
    16         try {
    17             System.out.println("threadA 开始执行第一个任务...");
    18             TimeUnit.SECONDS.sleep(1);
    19             System.out.println("threadA 第一个任务执行完毕...");
    20         }
    21         catch (InterruptedException e) {
    22             e.printStackTrace();
    23         }
    24         finally {
    25             if (countDownLatch != null) {
    26                 countDownLatch.countDown();
    27             }
    28         }
    29 
    30         try {
    31             System.out.println("threadA 开始执行第二个任务...");
    32             TimeUnit.SECONDS.sleep(3);
    33             System.out.println("threadA 第二个任务执行完毕...");
    34         }
    35         catch (InterruptedException e) {
    36             e.printStackTrace();
    37         }
    38         finally {
    39             // do something...
    40         }
    41 
    42         System.out.println("threadA end...");
    43     }
    44 
    45 }
     1 public class ThreadB extends Thread {
     2 
     3     private CountDownLatch countDownLatch;
     4 
     5     public ThreadB() {
     6     }
     7 
     8     public ThreadB(CountDownLatch countDownLatch) {
     9         this.countDownLatch = countDownLatch;
    10     }
    11 
    12     @Override
    13     public void run() {
    14         System.out.println("threadB start...");
    15 
    16         try {
    17             System.out.println("threadB 开始执行第一个任务...");
    18             TimeUnit.SECONDS.sleep(2);
    19             System.out.println("threadB 第一个任务执行完毕...");
    20         }
    21         catch (InterruptedException e) {
    22             e.printStackTrace();
    23         }
    24         finally {
    25             if (countDownLatch != null) {
    26                 countDownLatch.countDown();
    27             }
    28         }
    29 
    30         try {
    31             System.out.println("threadB 开始执行第二个任务...");
    32             TimeUnit.SECONDS.sleep(5);
    33             System.out.println("threadB 第二个任务执行完毕...");
    34         }
    35         catch (InterruptedException e) {
    36             e.printStackTrace();
    37         }
    38         finally {
    39             // do something...
    40         }
    41 
    42         System.out.println("threadB end...");
    43     }
    44 
    45 }
     1 public class JoinTest {
     2 
     3     public static void main(String[] args) throws InterruptedException {
     4         ThreadA threada = new ThreadA();
     5         ThreadB threadb = new ThreadB();
     6         threada.start();
     7         threadb.start();
     8         threada.join();
     9         threadb.join();
    10         System.out.println("joinTest end...");
    11     }
    12 
    13 }
     1 public class CountDownLatchTest {
     2 
     3     public static void main(String[] args) throws InterruptedException {
     4         CountDownLatch countDownLatch = new CountDownLatch(2);
     5         ExecutorService executorService = Executors.newCachedThreadPool();
     6         executorService.submit(new ThreadA(countDownLatch));
     7         executorService.submit(new ThreadB(countDownLatch));
     8         countDownLatch.await();
     9         System.out.println("countDownLatchTest end...");
    10         executorService.shutdown();
    11     }
    12 
    13 }

    为了方便我直接把countDownLatch.countDown()写到一个thread里面了,哈哈。

    首先我们观察ThreadA与ThreadB,可以发现他们分别有两个任务需要完成;如果你的业务场景都是需要在两个线程执行完后才会处理数据,那么join和CountDownLatch都可以实现。

    但如果你的场景和上述一样,只要在ThreadA、ThreadB完成第一个任务就可以处理后续逻辑的话,那么你就需要使用到CountDownLatch了;因为join没法处理那种线程只执行到某个节点就能唤醒的操作,它必须要当线程全部执行完后才能够唤醒,这就是为什么说CountDownLatch的控制粒度要比join细的原因了。

    CountDownLatch源码分析

    如果你把我前面所讲的AQS弄懂,那这个简直就是轻而易举,我这里就不再赘述了(偷懒了,哈哈)。

    查阅源码的时候你只要记住它的实现原理就可以了,CountDownLatch可以等待多个线程执行完毕后再执行某一件事情。

  • 相关阅读:
    js-禁止微信H5页面点击右上角菜单时出现“复制链接”,且分享仅支持微信分享
    js-获取用户移动端网络类型:wifi、4g、3g、2g...
    小程序-云开发部署流程(步骤二)
    小程序-(报错)请使用 2.2.3 或以上的基础库以使用云能力(步骤一)
    解决iOS10的Safari下Meta设置user-scalable=no无效的方法
    领域驱动, 事件驱动,测试驱动
    spring web项目中整合netty, akka
    why rpc
    nginx配置https证书
    org.apache.http.NoHttpResponseException
  • 原文地址:https://www.cnblogs.com/bzfsdr/p/13196712.html
Copyright © 2011-2022 走看看