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可以等待多个线程执行完毕后再执行某一件事情。

  • 相关阅读:
    Maidsafe-去中心化互联网白皮书
    The Top 20 Cybersecurity Startups To Watch In 2021 Based On Crunchbase
    Top 10 Blockchain Security and Smart Contract Audit Companies
    The 20 Best Cybersecurity Startups To Watch In 2020
    Blockchain In Cybersecurity: 11 Startups To Watch In 2019
    004-STM32+BC26丨260Y基本控制篇(阿里云物联网平台)-在阿里云物联网平台上一型一密动态注册设备(Android)
    涂鸦开发-单片机+涂鸦模组开发+OTA
    000-ESP32学习开发-ESP32烧录板使用说明
    03-STM32+Air724UG远程升级篇OTA(阿里云物联网平台)-STM32+Air724UG使用阿里云物联网平台OTA远程更新STM32程序
    03-STM32+Air724UG远程升级篇OTA(自建物联网平台)-STM32+Air724UG实现利用http/https远程更新STM32程序(TCP指令,单片机程序检查更新)
  • 原文地址:https://www.cnblogs.com/bzfsdr/p/13196712.html
Copyright © 2011-2022 走看看