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

目录

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

CountDownLatch是什么

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

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

CountDownLatch的伪代码如下所示:

//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类中定义的构造函数:

//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,负责所有特定的外部服务健康的检测。它删除了重复的代码和闭锁的中心控制代码。

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是一样的。

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:这个类是一个主启动类,它负责初始化闭锁,然后等待,直到所有服务都被检测完。

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;
    }
}

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

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);
    }
}

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 类中主要的方法?

原文链接: howtodoinjava 翻译: ImportNew.com - 张涛
译文链接: http://www.importnew.com/15731.html

CountDownLatch如何使用的更多相关文章

  1. 多线程条件通行工具——CountDownLatch

    CountDownLatch的作用是,线程进入等待后,需要计数器达到0才能通行. CountDownLatch(int)构造方法,指定初始计数. await()等待计数减至0. await(long, ...

  2. 【Java并发编程实战】-----“J.U.C”:CountDownlatch

    上篇博文([Java并发编程实战]-----"J.U.C":CyclicBarrier)LZ介绍了CyclicBarrier.CyclicBarrier所描述的是"允许一 ...

  3. 同步辅助类CountDownLatch用法

    CountDownLatch是一个同步辅助类,犹如倒计时计数器,创建对象时通过构造方法设置初始值,调用CountDownLatch对象的await()方法则使当前线程处于等待状态,调用countDow ...

  4. 架构师养成记--12.Concurrent工具类CyclicBarrier和CountDownLatch

    java.util.concurrent.CyclicBarrier 一组线程共同等待,直到达到一个公共屏障点. 举个栗子,百米赛跑中,所有运动员都要等其他运动员都准备好后才能一起跑(假如没有发令员) ...

  5. Java并发之CountDownLatch

    CountDownLatch是Java concurrent包下的一个同步工具.它可以让一个(或多个)线程等待,直到其他线程中的某些操作完成. 本质上是一个信号量,我们把它比作一个有N个插销的大门,它 ...

  6. Java多线程之CountDownLatch学习

    给出官网上的例子:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html Java中conc ...

  7. 【Java】JDK类 CountDownLatch

    一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 用给定的计数 初始化 CountDownLatch.由于调用了 countDown() 方法,所以在当前计数到达 ...

  8. 【JUC】JDK1.8源码分析之CountDownLatch(五)

    一.前言 分析完了CyclicBarrier后,下面分析CountDownLatch,CountDownLatch用于同步一个或多个任务,强制他们等待由其他任务执行的一组操作完成.CountDownL ...

  9. java多线程等待协调工作:CountDownLatch类的高级应用

    一:说明 基本上对于线程初步了解的人,都是使用synchronized来同步线程的,也确实,它也是可以满足一些常用的问题.那么我们来说一些它不能解决的问题(其实是不怎么好解决的问题,并不是真的不能解决 ...

  10. 【JAVA并发编程实战】4、CountDownLatch

    这是一个计数锁,说白了,就是当你上锁的时候,只有计数减少到0的时候,才会释放锁 package cn.xf.cp.ch05; public class TaskRunable implements R ...

随机推荐

  1. Android应用开发-网络编程(一)(重制版)

    网络图片查看器 1. 确定图片的网址 2. 发送http请求 URL url = new URL(address); // 获取客户端和服务器的连接对象,此时还没有建立连接 HttpURLConnec ...

  2. RSA加密算法的加密与解密

    转发原文链接:RSA加密算法加密与解密过程解析 1.加密算法概述 加密算法根据内容是否可以还原分为可逆加密和非可逆加密. 可逆加密根据其加密解密是否使用的同一个密钥而可以分为对称加密和非对称加密. 所 ...

  3. 承接Hololens内容定制外包

    近日,微软宣布第三批微软Hololens开发者版开始发货,包括:头显.头显手提包和一个遥控器.前两批开发者版本分别在今年3月30日和5月9日开始发货的. 第三批AR头显Hololens开发者版发货 虽 ...

  4. web api 开发记录

    1. 修改 api 返回时间格式 //配置返回的时间类型数据格式 GlobalConfiguration.Configuration.Formatters.JsonFormatter.Serializ ...

  5. java 事件监听 - 控件

    java 事件监听 //事件监听 //事件监听,写了一个小案例,点击按钮改变面板的颜色. import java.awt.*; import javax.swing.*; import java.aw ...

  6. mysql on Mac OS

    在新买的macbook pro15上安装了mysql,发现2个问题 一个是workbench基本无法正常退出,都要force quit 第二是我正常通过workbench连接后,查看系统log,会发现 ...

  7. 带你入门带你飞Ⅱ 使用Mocha + Chai + SuperTest测试Restful API in node.js

    目录 1. 简介 2. 准备开始 3. Restful API测试实战 Example 1 - GET Example 2 - Post Example 3 - Put Example 4 - Del ...

  8. 在.NET下多层架构企业管理系统的开发

    引言 .NET 框架是微软开发出的新一代开发平台.允许应用程序通过 Internet 进行通讯和共享数据,而不管所采用的是哪种操作系统.设备或编程语言.本文介绍的管理系统是在.NET平台下开发的,以极 ...

  9. 给iOS开发新手送点福利,简述文本属性Attributes的用法

    给iOS开发新手送点福利,简述文本属性Attributes的用法   文本属性Attributes 1.NSKernAttributeName: @10 调整字句 kerning 字句调整 2.NSF ...

  10. SimpleThreadPool实践

    前言 并发(Concurrency)一直谈论java绕不开的一个话题,从移动开发工程师到后端工程师,几乎所有的面试都要涉及到并发/多线程的一些问题.虽然多数时候我们使用线程池,都是已经实现好的框架—— ...