java并发编程实战 pdf java并发编程JUC第九篇:CountDownLatch线程同步


java并发编程实战 pdf java并发编程JUC第九篇:CountDownLatch线程同步

文章插图
在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口、ArrayBlockingQueue、DelayQueue、LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue、BlockingDeque接口、ConcurrentHashMap , 本文为系列文章第九篇 。
【java并发编程实战 pdf java并发编程JUC第九篇:CountDownLatch线程同步】CountDownLatch是一种线程同步辅助工具 , 它允许一个或多个线程等待其他线程正在执行的一组操作完成 。CountDownLatch的概念在java并发编程中非常常见 , 面试也会经常被问到 , 所以一定要好好理解掌握 。在这篇文章中 , 我将介绍以下几点
  • CountDownLatch是什么?
  • CountDownLatch 如何工作
  • CountDownLatch 代码例子
CountDownLatch是什么?CountDownLatch与其他并发编程工具类 , 如CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue等在java.util.concurrent包中与JDK 1.5一起被引入 。CountDownLatch能让一个java线程等待其他线程完成任务 , 比如Application的主线程等待 , 直到其他负责启动框架服务的服务线程完成所有服务的启动 。
CountDownLatch用线程数来初始化一个计数器 , 每当一个线程完成执行时 , 这个计数器就会递减 。当计数为零时 , 表示所有线程都已完成执行 , 处于等待状态的主线程可以继续执行 。
java并发编程实战 pdf java并发编程JUC第九篇:CountDownLatch线程同步

文章插图
下面我们使用伪代码的方式描述CountDownLatch 的作用
  • 主线程启动 , 并为N个线程(假设n=3)初始化CountDownLatch(n)
  • 启动n个线程
  • 主线程阻塞等待
  • 线程1执行完成 , CountDownLatch -1 = 2 , 主线程继续阻塞
  • 线程3执行完成 , CountDownLatch -1 = 1 , 主线程继续阻塞
  • 线程4执行完成 , CountDownLatch -1 = 0 , 主线程恢复执行
CountDownLatch 如何工作CountDownLatch.java类里面定义了一个构造函数 。count实质上是线程数 , 这个值只能设置一次 , CountDownLatch没有提供方法来重置这个数 。
CountDownLatch.public CountDownLatch(int count) {...}使用CountDownLatch的主线程要去等待其他线程执行完成 , 所以这个主线程必须在启动其他线程后立即调用 CountDownLatch.await() 方法 , 该方法阻塞主线程处于等待状态 , 直到其他线程执行完毕 , 才会停止阻塞 。
其他N个线程必须有CountDownLatch对象的引用 , 因为它们需要通知CountDownLatch对象它们已经完成任务 。这个通知是由方法CountDownLatch.countDown()来完成的 , 每调用一次该方法 , 就会将构造函数中设置的初始计数count减少1 , 所以当所有N个线程都调用了这个方法后count计数达到0 , 主线程就可以不受await()方法阻塞恢复执行了 。
所以CountDownLatch特别适合于那些需要等待N个线程完成后再开始执行的场景 。例如一个应用程序的启动类 , 在处理用户请求之前 , 要确保所有N个外部系统都是处于运行状态的 。
CountDownLatch 代码例子假设我们的应用程序主线程启动之前 , 要检查另外4个程序是否准备就绪 , 只有其他的4个程序准备就绪 , 我们的主程序才能继续执行 。就可以使用下面的代码来操作:
import java.util.concurrent.CountDownLatch;public class Tester {   public static void main(String args[]) {      //设置计数器 counter = 4  , 等于线程数      CountDownLatch countDownLatch = new CountDownLatch(4);      Thread app1 = new Thread(new Application("App1",  countDownLatch));      Thread app2 = new Thread(new Application("App2",  countDownLatch));                Thread app3 = new Thread(new Application("App3",  countDownLatch));      Thread app4 = new Thread(new Application("App4",  countDownLatch));         // 启动多线程去检查其他四个程序的可用状态      app1.start();      app2.start();      app3.start();      app4.start();      try {         //主线程调用await进行等待 , 等待上述四个线程正常完成         countDownLatch.await();                     //上述四个线程检查的应用程序启动正常之后, 打印如下信息         System.out.println("All applications are up and running.");      } catch(InterruptedException e) {         System.out.println(e.getMessage());      }           }}子线程程序 , 每一个线程都持有countDownLatch对象 , 线程正常执行完成之时 , 使用countDownLatch.countDown()方法将countDownLatch对象的计数器减1 。
class Application implements Runnable {   private String name; //应用程序名称   private CountDownLatch countDownLatch;    public Application(String name, CountDownLatch countDownLatch) {      this.name = name;      this.countDownLatch = countDownLatch;   }   public void run() {      try {         System.out.println(name + " started. ");         Thread.sleep(1000);      } catch (InterruptedException e) {         System.out.println(e.getMessage());      }      System.out.println( name + " is Up and running.");      //将countDownLatch计数器的值减1      countDownLatch.countDown();       }}上述程序的打印输出结果是 , 可以结合输出结果去理解上文中讲述的CountDownLatch 工作原理:
App2 started.  App3 started.  App1 started.  App4 started.  App1 is Up and running.App3 is Up and running.App4 is Up and running.App2 is Up and running.All applications are up and running.欢迎关注我的博客 , 里面有很多精品合集
  • 本文转载注明出处(必须带连接 , 不能只转文字):字母哥博客 。
觉得对您有帮助的话 , 帮我点赞、分享!您的支持是我不竭的创作动力!。另外 , 笔者最近一段时间输出了如下的精品内容 , 期待您的关注 。
  • 《手摸手教你学Spring Boot2.0》
  • 《Spring Security-JWT-OAuth2一本通》
  • 《实战前后端分离RBAC权限管理系统》
  • 《实战SpringCloud微服务从青铜到王者》
  • 《VUE深入浅出系列》