• 并发编程工具之一/多线程控制工具类:CountDownLatch 用法


    原文来自:https://blog.csdn.net/Somhu/article/details/78614783

            https://www.relaxheart.cn/to/master/blog?uuid=83

    CountDownLatch 用法

        CountDownLatch是java.util.concurrent包中一个类,CountDownLatch只要提供的机制是多个(具体数量等于初始化CountDownLatch时count的值)线程都达到了预期状态或者完成了预期工作时触发事件,其他线程可以等待这个事件来触发自己后续的工作。等待的线程可以是多个,即CountDownLatch可以唤醒多个等待的线程。

    到达自己预期状态的线程会调用CountDownLatch的countDown方法,而等待的线程会调用CountDownLatch的await方法。 

    主要方法讲解:

    CountDownLatch(int count) //实例化一个倒计数器,count指定计数个数
    countDown() // 计数减一
    await() //等待,当计数减到0时,所有线程并行执行

      CountDownLatch在工作的多个场景被使用,算是用的很频繁的了,比如我司API接口要求响应时间在200ms以内,但是如果一个接口内部依赖多个三方/外部服务,那串行调用接口的RT必然很久,所以个人用的最多的是接口RT优化场景,内部服务并行调用。

    对于倒计数器,一种典型的场景就是火箭发射。在火箭发射前,为了保证万无一失,往往还要进行各项设备、仪器的检测。只有等到所有的检查完毕后,引擎才能点火。那么在检测环节当然是多个检测项可以同时进行的。

      代码实现:

      

     1 public class CountDownLatchDemo implements Runnable{ 
     2     static final CountDownLatch latch = new CountDownLatch(10); 
     3     static final CountDownLatchDemo demo = new CountDownLatchDemo(); 
     4 
     5     @Override 
     6     public void run() {
     7          // 模拟检查任务 
     8         try {
     9              Thread.sleep(new Random().nextInt(10) * 1000); 
    10              System.out.println("check complete"); 
    11 
    12              //计数减一 
              latch.countDown();
    13 } catch (InterruptedException e) { 14 e.printStackTrace(); 15 } 16 } 17 18 19 public static void main(String[] args) throws InterruptedException { 20 ExecutorService exec = Executors.newFixedThreadPool(10); 21 22 for (int i=0; i<10; i++){ 23 exec.submit(demo); 24 } 25 26 // 等待检查 27 latch.await(); 28 29 // 发射火箭 30 System.out.println("Fire!"); 31 32 // 关闭线程池 33 exec.shutdown(); 34 } 35 } 36 37


     

    结合以下几个例子,可以快速掌握这个这个类的基本使用方法: 

    例一:

     1 public static void main(String[] args) throws InterruptedException {
     2     CountDownLatch countDown = new CountDownLatch(1);
     3         CountDownLatch await = new CountDownLatch(5);
     4 
     5         // 依次创建并启动处于等待状态的5个MyRunnable线程
     6         for (int i = 0; i < 5; ++i) {
     7             new Thread(new MyRunnable(countDown, await)).start();
     8         }
     9 
    10         System.out.println("用于触发处于等待状态的线程开始工作......");
    11         System.out.println("用于触发处于等待状态的线程工作完成,等待状态线程开始工作......");
    12         countDown.countDown();
    13         await.await();
    14         System.out.println("Bingo!");
    15 }
    16 
    17 public class MyRunnable implements Runnable {
    18 
    19     private final CountDownLatch countDown;
    20     private final CountDownLatch await;
    21 
    22     public MyRunnable(CountDownLatch countDown, CountDownLatch await) {
    23         this.countDown = countDown;
    24         this.await = await;
    25     }
    26 
    27     public void run() {
    28         try {
    29             countDown.await();//等待主线程执行完毕,获得开始执行信号...
    30             System.out.println("处于等待的线程开始自己预期工作......");
    31             await.countDown();//完成预期工作,发出完成信号...
    32         } catch (InterruptedException e) {
    33             e.printStackTrace();
    34         }
    35     }
    36 }
    37 运行结果:
    38 用于触发处于等待状态的线程开始工作......
    39 用于触发处于等待状态的线程工作完成,等待状态线程开始工作......
    40 处于等待的线程开始自己预期工作......
    41 处于等待的线程开始自己预期工作......
    42 处于等待的线程开始自己预期工作......
    43 处于等待的线程开始自己预期工作......
    44 处于等待的线程开始自己预期工作......
    45 Bingo!

    例子二:

     1 public class TestDemo2 {
     2 
     3     public static void main(String[] args) throws InterruptedException {
     4         ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5));
     5         int count = 10;
     6         final CountDownLatch latch = new CountDownLatch(count);
     7 
     8         for (int i = 0; i < count; i++) {
     9             threadPool.execute(new MyRunnable1(latch, i));
    10         }
    11 
    12         latch.await();
    13         System.err.println("等待线程被唤醒!");
    14         threadPool.shutdown();
    15     }
    16 }
    17 
    18 class MyRunnable1 implements Runnable {
    19 
    20     CountDownLatch latch = null;
    21     int i;
    22 
    23     public MyRunnable1(CountDownLatch latch, int i) {
    24         this.latch = latch;
    25         this.i = i;
    26     }
    27 
    28     @Override
    29     public void run() {
    30         System.err.println("线程" + i +"完成了操作...");
    31         try {
    32             Thread.currentThread();
    33             Thread.sleep(4000);
    34         } catch (InterruptedException e) {
    35             e.printStackTrace();
    36         }
    37         latch.countDown();
    38     }
    39 
    40 }
    41 运行结果:
    42 线程0完成了操作...
    43 线程3完成了操作...
    44 线程2完成了操作...
    45 线程1完成了操作...
    46 线程4完成了操作...//暂停4秒
    47 线程5完成了操作...
    48 线程6完成了操作...
    49 线程8完成了操作...
    50 线程7完成了操作...
    51 线程9完成了操作...//暂停4秒
    52 等待线程被唤醒!
  • 相关阅读:
    c++父类指针子类指针转化分析
    setbuf手册
    c++细节
    cf727e
    总结
    UVa 10192 Vacation (最长公共子序列)
    HUNNU 11313 最长公共子序列(LCS)
    HDU 2069 Coin Change (经典DP)
    UVa 674 Coin Change (经典DP)
    UVa 10131 Is Bigger Smarter? (LDS+数据结构排序)
  • 原文地址:https://www.cnblogs.com/hanxue53/p/11114792.html
Copyright © 2020-2023  润新知