正如每个Java文档所描述的那样,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。在Java并发中,countdownlatch的概念是一个常见的面试题,所以一定要确保你很好的理解了它。在这篇文章中,我将会涉及到在Java并发编 程中跟CountDownLatch相关的以下几点:

目录

  • CountDownLatch是什么?
  • CountDownLatch如何工作?
  • 在实时系统中的应用场景
  • 应用范例
  • 常见的面试题

CountDownLatch是什么

CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它们都存在于java.util.concurrent包下。CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。

CountDownLatch的伪代码如下所示:

1
2
3
4
5
6
//Main thread start
//Create CountDownLatch for N threads
//Create and start N threads
//Main thread wait on latch
//N threads completes there tasks are returns
//Main thread resume execution

CountDownLatch如何工作

CountDownLatch.java类中定义的构造函数:

1
2
//Constructs a CountDownLatch initialized with the given count.
public void CountDownLatch(int count) {...}

构造器中的计数值(count)实际上就是闭锁需要等待的线程数量。这个值只能被设置一次,而且CountDownLatch没有提供任何机制去重新设置这个计数值

与CountDownLatch的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。

其他N 个线程必须引用闭锁对象,因为他们需要通知CountDownLatch对象,他们已经完成了各自的任务。这种通知机制是通过 CountDownLatch.countDown()方法来完成的;每调用一次这个方法,在构造函数中初始化的count值就减1。所以当N个线程都调 用了这个方法,count的值等于0,然后主线程就能通过await()方法,恢复执行自己的任务。

在实时系统中的使用场景

让我们尝试罗列出在java实时系统中CountDownLatch都有哪些使用场景。我所罗列的都是我所能想到的。如果你有别的可能的使用方法,请在留言里列出来,这样会帮助到大家。

  1. 实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。
  2. 开始执行前等待n个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。
  3. 死锁检测:一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。

CountDownLatch使用例子

在这个例子中,我模拟了一个应用程序启动类,它开始时启动了n个线程类,这些线程将检查外部系统并通知闭锁,并且启动类一直在闭锁上等待着。一旦验证和检查了所有外部服务,那么启动类恢复执行。

BaseHealthChecker.java:这个类是一个Runnable,负责所有特定的外部服务健康的检测。它删除了重复的代码和闭锁的中心控制代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public abstract class BaseHealthChecker implements Runnable {
    private CountDownLatch _latch;
    private String _serviceName;
    private boolean _serviceUp;
    //Get latch object in constructor so that after completing the task, thread can countDown() the latch
    public BaseHealthChecker(String serviceName, CountDownLatch latch)
    {
        super();
        this._latch = latch;
        this._serviceName = serviceName;
        this._serviceUp = false;
    }
    @Override
    public void run() {
        try {
            verifyService();
            _serviceUp = true;
        } catch (Throwable t) {
            t.printStackTrace(System.err);
            _serviceUp = false;
        } finally {
            if(_latch != null) {
                _latch.countDown();
            }
        }
    }
    public String getServiceName() {
        return _serviceName;
    }
    public boolean isServiceUp() {
        return _serviceUp;
    }
    //This methos needs to be implemented by all specific service checker
    public abstract void verifyService();
}

NetworkHealthChecker.java:这个类继承了BaseHealthChecker,实现了verifyService()方法。DatabaseHealthChecker.javaCacheHealthChecker.java除了服务名和休眠时间外,与NetworkHealthChecker.java是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class NetworkHealthChecker extends BaseHealthChecker
{
    public NetworkHealthChecker (CountDownLatch latch)  {
        super("Network Service", latch);
    }
    @Override
    public void verifyService()
    {
        System.out.println("Checking " + this.getServiceName());
        try
        {
            Thread.sleep(7000);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        System.out.println(this.getServiceName() + " is UP");
    }
}

ApplicationStartupUtil.java:这个类是一个主启动类,它负责初始化闭锁,然后等待,直到所有服务都被检测完。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class ApplicationStartupUtil
{
    //List of service checkers
    private static List<BaseHealthChecker> _services;
    //This latch will be used to wait on
    private static CountDownLatch _latch;
    private ApplicationStartupUtil()
    {
    }
    private final static ApplicationStartupUtil INSTANCE = new ApplicationStartupUtil();
    public static ApplicationStartupUtil getInstance()
    {
        return INSTANCE;
    }
    public static boolean checkExternalServices() throws Exception
    {
        //Initialize the latch with number of service checkers
        _latch = new CountDownLatch(3);
        //All add checker in lists
        _services = new ArrayList<BaseHealthChecker>();
        _services.add(new NetworkHealthChecker(_latch));
        _services.add(new CacheHealthChecker(_latch));
        _services.add(new DatabaseHealthChecker(_latch));
        //Start service checkers using executor framework
        Executor executor = Executors.newFixedThreadPool(_services.size());
        for(final BaseHealthChecker v : _services)
        {
            executor.execute(v);
        }
        //Now wait till all services are checked
        _latch.await();
        //Services are file and now proceed startup
        for(final BaseHealthChecker v : _services)
        {
            if( ! v.isServiceUp())
            {
                return false;
            }
        }
        return true;
    }
}

现在你可以写测试代码去检测一下闭锁的功能了。

1
2
3
4
5
6
7
8
9
10
11
12
public class Main {
    public static void main(String[] args)
    {
        boolean result = false;
        try {
            result = ApplicationStartupUtil.checkExternalServices();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("External services validation completed !! Result was :: "+ result);
    }
}

1
2
3
4
5
6
7
8
9
Output in console:
Checking Network Service
Checking Cache Service
Checking Database Service
Database Service is UP
Cache Service is UP
Network Service is UP
External services validation completed !! Result was :: true

常见面试题

可以为你的下次面试准备以下一些CountDownLatch相关的问题:

  • 解释一下CountDownLatch概念?
  • CountDownLatch 和CyclicBarrier的不同之处?
  • 给出一些CountDownLatch使用的例子?
  • CountDownLatch 类中主要的方法?

下载上述例子的源代码,请点击如下链接:

  • 源码下载

也上传一份到csdn了,可免费下载http://download.csdn.net/detail/u012373717/9674633

转载于:https://www.cnblogs.com/felixzh/p/6036151.html

什么时候使用CountDownLatch相关推荐

  1. Java并发编程之CountDownLatch、CyclicBarrier和Semaphore

    前言 本文为对CountDownLatch.CyclicBarrier.Semaphore的整理使用 CountDownLatch CountDownLatch类位于java.util.concurr ...

  2. java并发之同步辅助类CyclicBarrier和CountDownLatch

    CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier).它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门, ...

  3. java 并发统计_java并发编程|CountDownLatch计数器

    0x01,CountDownLatch介绍 CountDownLatch是一个计数器,作为java并发编程中三个组件之一,这个组件的使用频率还是很多的.这里分享下自己画的java并发编程组件的图,后面 ...

  4. JAVA中的并发工具 -- CountDownLatch、CyclicBarrier、Semaphore

    2019独角兽企业重金招聘Python工程师标准>>> CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操作. CountDownLatc ...

  5. Java常用多线程辅助工具---countdownLatch

    为什么80%的码农都做不了架构师?>>> 前言 上一篇博文说到semaphore,一个加强版的synchronized,该多线程辅助工具适用于控制对资源操作或者访问的场景.现在有一张 ...

  6. 一文搞懂 CountDownLatch 用法和源码!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! CountDownLatch 是多线程控制的一种工具,它被 ...

  7. CountDownLatch的实现分析

    CountDownLatch CountdownLatch 是 JDK 并发包中提供的并发工具类,其允许一个或多个线程等待其他线程完成操作.常用作将一个任务拆分成多个子任务同时执行,只有子任务都执行完 ...

  8. LeetCode 1195. Fizz Buzz Multithreaded--并发系列题目--Java 解法--AtomicInteger/CountDownLatch/CyclicBarrier

    题目地址:Fizz Buzz Multithreaded - LeetCode Write a program that outputs the string representation of nu ...

  9. CycliBarriar和CountdownLatch(计数器)

    CyclicBarrier可以重复使用,而CountdownLatch不能重复使用. countDownLatch这个类使一个线程等待其他线程各自执行完毕再执行. 是通过一个计数器来实现的,计数器的初 ...

  10. Redisson 分布式锁源码 11:Semaphore 和 CountDownLatch

    前言 Redisson 除了提供了分布式锁之外,还额外提供了同步组件,Semaphore 和 CountDownLatch. Semaphore 意思就是在分布式场景下,只有 3 个凭证,也就意味着同 ...

最新文章

  1. Pyinstaller 打包 torch 后执行失败 OSError: could not get source code
  2. 剑指offer:数组中只出现一次的数字
  3. 外包 银行数字签名U盘的用法
  4. 2020年“内容、服务”征集
  5. Atitit.5gl 第五代语言编程语言 PROLOG教程  人工智能语言的标准 与实现
  6. mysql 逻辑处理_mysql 逻辑查询处理流程
  7. TPFanControl v0.62 + 汉化补丁
  8. 深入解析Node.js setTimeout方法的执行过程
  9. 手机Web 开发中图片img 如何等比例缩放
  10. OLAP-druid-大数据Week13-DAY2-druid
  11. 软件设计师 下午题第4题
  12. [职业规划]电子通信专业大学之路
  13. VS2017好用的插件推荐
  14. 眼睛容易干燥疲劳怎么办?
  15. 八爪鱼取消Ajax加载数据,谁知道八爪鱼采集器设置了循环翻页采集怎么才采集十几个数据就停下不动了...
  16. Python刷博客简易版
  17. 免费的安装算量软件有哪些?鹏业安装算量与品茗安装算量对比
  18. qq登录无法连接服务器未响应,win7登录qq提示腾讯qq未响应的解决方法
  19. Android 百度地图marker中图片不显示的解决方案
  20. 在linux用锐捷客户端上校园网

热门文章

  1. python爬虫模拟登录人人网
  2. python网络爬虫系列(四)——requests模块
  3. LeetCode MySQL 1549. The Most Recent Orders for Each Product
  4. LeetCode MySQL 1194. 锦标赛优胜者
  5. LeetCode 1418. 点菜展示表(哈希map)
  6. LeetCode 686. 重复叠加字符串匹配
  7. LeetCode 297. 二叉树的序列化与反序列化(前序遍历层序遍历)
  8. java异步处理同步化_java 异步查询转同步多种实现方式:循环等待,CountDownLatch,Spring EventListener,超时处理和空循环性能优化...
  9. python 控件叠加_如何将图像应用于控件背景(叠加)
  10. 【安利向】入坑半年的GPU云平台,三分钟训练起飞!xiu~