什么时候使用CountDownLatch

正如每个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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/489672.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java父包引用_父类引用指向子类对象(java)

从对象的内存角度来理解试试.假设现在有一个父类Father,它里面的变量需要占用1M内存.有一个它的子类Son,它里面的变量需要占用0.5M内存.现在通过代码来看看内存的分配情况:Father f new Father();//系统将分配1M内存.Son s new Son();//系统将分配1.5M内存!因为子类中有一个隐…

科技角逐:中美的人工智能布局

来源&#xff1a;人机与认知实验室2017年以来&#xff0c;与人工智能相关的国家级战略密集出台&#xff0c;社会关于人工智能的大讨论激烈展开&#xff0c;各国政府关于人工智能发展的思路也逐渐清晰。中美作为两大科技强国&#xff0c;都在人工智能领域投入巨大&#xff0c;有…

python中scale_Python中的Log-scale mathplotlib?

我试图拟合对数正态曲线&#xff0c;但我不知道如何将y(和x轴)更改为对数刻度&#xff1f;我尝试使用logspace而不是linspace&#xff0c;但是遇到了一个错误OverflowError: cannot convert float infinity to integer我试过了&#xff1a;^{pr2}$但这似乎也不管用。我附上了我…

akka kafka java_当使用websocket连接时,使用akka-stream-kafka从kafka主题获取最后一条消息...

使用David van Geest非常巧妙地描述的方法&#xff0c;我能够避免在客户端连接时获取任何上游数据here归结为在Consumer上有一个BroadcastHub&#xff1a;val liveSource Consumer.plainSource(consumerSettings, Subscriptions.topics(topic1, topic2)).map(kafkaObject >…

android px,dp,sp大小转换工具

package com.voole.playerlib.util;import android.content.Context;/*** Android大小单位转换工具类<br/>* * float scale context.getResources().getDisplayMetrics().density;*/ public class DisplayUtil {/*** 将px值转换为dip或dp值&#xff0c;保证尺寸大小不变…

工业物联网的应用领域与方向

&#xff08;图片来自pixabay&#xff09;来源&#xff1a;OFweek工控从一定程度上&#xff0c;物联网可以说是个“旧瓶装新酒”的概念&#xff0c;提出物联网——IoT&#xff08;Internet of things&#xff09;这个概念的确是一种创新&#xff0c;但是要把这个创新与传统的M2…

mysql count里面能加条件吗_select count(1) 和 count(*),哪个性能更好?

相信很多小伙伴都想了解 count(1) 和 count(*) 的性能问题 &#xff0c;今天给大家做一下测试。声明&#xff1a;本文使用MySql数据库&#xff0c;数据库表里面有100万条数据。先测试 count(*)可以看出&#xff0c;count(*) 用时间差不多15s.再测试 count(1)看到这个数据&#…

PDA 收银系统PDA手持打印扫描枪 销售开单 收银 扫描打印一体机

在零售方面也有很好的应用。如在一些高端品牌零售店,营业员可以随身导购&#xff0c;一站式完成了商品销售和收银&#xff0c;很是受消费者追捧&#xff0c;符合了企业对客户体验以及行业领先的追求。 PDA收银系统是一款多功能可以取代专业收银机的收银系统&#xff0c;适合各种…

如何获取投票提交地址_简单实用 | 2019全国医院擂台赛投票攻略(县域版)

作者&#xff1a;用户大当家2019改善医疗服务行动全国医院擂台赛案例征集环节结束。截止8月15日24时&#xff0c;城市组提交案例2196个&#xff0c;县域组提交案例1087个&#xff0c;总计3283个案例&#xff0c;数量再度创纪录。首先为积极改善医疗服务的您点赞。接下来&#x…

java 16 binary_【图片】【困扰】java(tm) platform se binary 已停止工作该如何是好【minecraft吧】_百度贴吧...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼Completely ignored arguments: [--nativeLauncherVersion, 307][18:26:56] [Client thread/INFO]: Setting user: XXX[18:26:58] [Client thread/WARN]: Skipping bad option: lastServer:[18:26:58] [Client thread/INFO]: LWJGL…

菲尔兹奖数学家丘成桐:人工智能中的数学理论尚无很大突破

来源&#xff1a;机器人10月17日&#xff0c;在2019中关村论坛上&#xff0c;菲尔兹奖首位华人获得者、美国国家科学院院士、哈佛大学教授丘成桐发表主旨演讲。他呼吁国家应重视基础科学和数学的发展。一个国家的强大和长治久安&#xff0c;离不开强大的基础科学&#xff0c;没…

python定义类时括号_为什么在定义类时括号是可选的,而在定义函数时括号是必需的?...

我认为你的问题的答案只是语法。这正是Python的设置方式&#xff0c;但我对它的设置方式的看法是&#xff1a;我认为函数来自数学&#xff0c;比如&#xff1a;f(x) x所以当计算机编程语言被创造出来的时候&#xff0c;从模拟数学到编程语言似乎有某种逻辑上的连续性。另一方面…

java bean set_JavaBean自动生成get和set方法

android计算每个目录剩余空间丶总空间以及SD卡剩余空间ublic class MemorySpaceCheck { /** * 计算剩余空间 * param path * return */ public static String getAvail ...ionic&plus;angularjs开发hybrid App&lpar;环境配置&plus;创建测试项目&rpar;本文使用的…

从地心到宇宙,再到治疗癌症与“赋灵”智能,这届腾讯WE都聊了些啥?

来源&#xff1a;腾讯科学WE大会Hod Lipson这人是谁————哥伦比亚大学创意机器实验室主任&#xff0c;致力于开发机器人的创造力&#xff0c;让机器人拥有自己的思想和情感。说了些啥————大概100年来我们一直试图建造有自我意识的机器人&#xff0c;我们希望这些机器人…

复制文件,并重命名

总体思路&#xff1a;1. 先复制文件到指定目录下&#xff1b; 2. 根据需要&#xff0c;修改文件名称。 &#xff08;1&#xff09;复制文件 实现代码&#xff1a; 例如&#xff1a;把“D:\照片”目录下的文件复制到“D:\姓名”目录下。 /** * 描述&#xff1a;复制文件 到 目标…

python计算入门_Python入门教程02-01(计算机核心基础)

python入门课程第二章-计算机核心基础Python入门教程01-01(ATM购物车)学习过后&#xff0c;我们需要了解一下计算机的核心基础&#xff0c;目标就是为了让后面更好的理解python这门语言&#xff0c;更容易接受后续新的课程难点。下面我们来一起学习第二章吧~~~~一 引子:接下来一…

php字符串反转abcdefg_php中实现字符串翻转的方法

字符串:$str "abcdefg";方法一(直接使用php自带函数strrev($str))print_r(strrev($str));使用for循环方式,str_split($str)$newArrOne [];//初始化一个新的数组$newStrOne ;//初始化一个新的字符串$newArrOne str_split($str);$arrCount count($newArrOne);for …

RISC-V浪潮来袭!115页PPT超详论述,如何与ARM争锋!(一)

来源&#xff1a;芯潮近两年来&#xff0c;在ARM和Intel主导的竞争格局中&#xff0c;一个新的开源指令集架构RISC-V在芯片江湖声名鹊起。面对来势汹汹的AI和IoT浪潮&#xff0c;RISC-V提供了一种高能效低成本解决方案&#xff0c;吸引了谷歌、高通、IBM、镁光、西部数据、三星…

redisb并发访问慢出现的问题

最近项目一上线&#xff0c;就问题颇多&#xff0c;本地测试&#xff0c;ok&#xff0c;上线后&#xff0c;大用户量的时候&#xff0c;顶不住。用了一个礼拜的时间发现的问题&#xff0c;总结下来。 项目是netty4.0&#xff0c;reids2.8,nginx等框架。目前是4台proxy服务器&am…

python idle运行anaconda_在Python IDLE 下调用anaconda中的库教程

大家都知道&#xff0c;Anaconda是一个开源的Python发行版本&#xff0c;其包含了conda、Python等180多个科学包及其依赖项。下载了anaconda我们可以很方便的随时调用这里面的库。原先我自己在Python官网下载了python 3.7开发环境&#xff0c;anaconda的后面下载的&#xff0c;…