在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口、ArrayBlockingQueue、DelayQueue、LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue、BlockingDeque接口、ConcurrentHashMap,本文为系列文章第九篇。

CountDownLatch是一种线程同步辅助工具,它允许一个或多个线程等待其他线程正在执行的一组操作完成。CountDownLatch的概念在java并发编程中非常常见,面试也会经常被问到,所以一定要好好理解掌握。在这篇文章中,我将介绍以下几点

  • CountDownLatch是什么?
  • CountDownLatch 如何工作
  • CountDownLatch 代码例子

CountDownLatch是什么?

CountDownLatch与其他并发编程工具类,如CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue等在java.util.concurrent包中与JDK 1.5一起被引入。CountDownLatch能让一个java线程等待其他线程完成任务,比如Application的主线程等待,直到其他负责启动框架服务的服务线程完成所有服务的启动。

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.

欢迎关注我的博客,里面有很多精品合集

  • 本文转载注明出处(必须带连接,不能只转文字):字母哥博客

觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。

java并发编程JUC第九篇:CountDownLatch线程同步的更多相关文章

  1. Java并发编程(您不知道的线程池操作), 最受欢迎的 8 位 Java 大师,Java并发包中的同步队列SynchronousQueue实现原理

    Java_并发编程培训 java并发程序设计教程 JUC Exchanger 一.概述 Exchanger 可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchan ...

  2. Java并发编程(您不知道的线程池操作)

    Java并发编程(您不知道的线程池操作) 这几篇博客,一直在谈线程,设想一下这个场景,如果并发的线程很多,然而每个线程如果执行的时间很多的话,这样的话,就会大量的降低系统的效率.这时候就可以采用线程池 ...

  3. java并发编程笔记(五)——线程安全策略

    java并发编程笔记(五)--线程安全策略 不可变得对象 不可变对象需要满足的条件 对象创建以后其状态就不能修改 对象所有的域都是final类型 对象是正确创建的(在对象创建期间,this引用没有逸出 ...

  4. java并发编程笔记(三)——线程安全性

    java并发编程笔记(三)--线程安全性 线程安全性: ​ 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现 ...

  5. 【Java并发编程】之二:线程中断

    [Java并发编程]之二:线程中断 使用interrupt()中断线程 ​ 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一 ...

  6. java并发编程笔记(七)——线程池

    java并发编程笔记(七)--线程池 new Thread弊端 每次new Thread新建对象,性能差 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM 缺 ...

  7. java并发编程JUC第十篇:CyclicBarrier线程同步

    在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...

  8. java并发编程系列原理篇--JDK中的通信工具类Semaphore

    前言 java多线程之间进行通信时,JDK主要提供了以下几种通信工具类.主要有Semaphore.CountDownLatch.CyclicBarrier.exchanger.Phaser这几个通讯类 ...

  9. 《Java并发编程实战》学习笔记 线程安全、共享对象和组合对象

    Java Concurrency in Practice,一本完美的Java并发参考手册. 查看豆瓣读书 推荐:InfoQ迷你书<Java并发编程的艺术> 第一章 介绍 线程的优势:充分利 ...

随机推荐

  1. ColyseusJS 轻量级多人游戏服务器开发框架 - 中文手册(上)

    快速上手多人游戏服务器开发.后续会基于 Google Agones,更新相关 K8S 运维.大规模快速扩展专用游戏服务器的文章.拥抱️原生 Cloud-Native! 快速开始 在开始之前,让我们确保 ...

  2. Nacos 1.3.2 启动报错[db-load-error]load jdbc.properties error

    原因: 1.3.2版本Nacos默认启动模式为集群,在startup.cmd文件中第27行可以看到. 解决办法: 一.选择以默认的集群方式启动,就需要配置集群所需环境: 1.创建持久化数据库,推荐使用 ...

  3. Spring Security 入门篇

    本文是一个笔记系列,目标是完成一个基于角色的权限访问控制系统(RBAC),有基本的用户.角色.权限管理,重点在Spring Security的各种配置.万丈高楼平地起,接下来,一步一步,由浅入深,希望 ...

  4. 全套visio版本安装教程及下载地址

    1:visio 2003 安装教程及下载地址 https://mp.weixin.qq.com/s/vhJUagKBz3vM-Dru0cwYow 2:visio 2007 安装教程及下载地址 http ...

  5. Windows bat批处理删除指定N天前的文件

    1:新建批处理文件:del_old_file.bat,更改系统时间为7天前,在c盘sql back 目录下新建测试文件,再将系统时间改为正确时间 2:编辑内容: rem 删除C:\sql back目录 ...

  6. 本地Markdown上传图片

    本地Markdown上传图片 1.上传本地markdown文件到博客园 使用工具pycnblog 下载:https://github.com/dongfanger/PyCnblog 查看READ ME ...

  7. RTTI之dynamic_cast运算符

    #include <iostream> #include <cstdlib> #include <ctime> using std::cout; class Gra ...

  8. 【BUAA软工】提问回顾与个人总结

    链接到以前提问题的博客 在之前的博客我曾经提问过以下几个问题 为什么单元测试必须由写程序的人完成? 过早优化,过早泛华:何时为过早? 为何使用goto语句? 用户需求分析:分而治之,如何分? 兼容性测 ...

  9. 【BUAA软工】结对编程作业

    项目 内容 课程:2020春季软件工程课程博客作业(罗杰,任健) 博客园班级链接 作业:BUAA软件工程结对编程项目作业 作业要求 课程目标 学习大规模软件开发的技巧与方法,锻炼开发能力 作业目标 完 ...

  10. 3. java基础语法

    3.1 注释(理解) 注释是对代码的解释和说明文字,可以提高程序的可读性,因此在程序中添加必要的注释文字十分重要.Java中的 注释分为三种: 单行注释.单行注释的格式是使用//,从//开始至本行结尾 ...