java并发编程之CountDownLatch

CountDownLatch是一个同步辅助工具,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。CountDownLatch概念是很常见的面试问题,Java并发,所以一定要充分理解它。在这篇文章中,我将介绍与java并发中的CountDownLatch相关的以下几点。

这篇文章中的章节:

什么是CountDownLatch?
CountDownLatch如何工作?
实时应用中可能的用法
示例应用
常见的面试问题

什么是CountDownLatch?

CountDownLatch 与JDK 1.5以及 java.util.concurrent包中的CyclicBarrier,Semaphore,ConcurrentHashMapBlockingQueue等其他并发实用程序一起引入。此类使java线程等待,直到其他线程集完成其任务。例如,应用程序的主线程要等待,直到负责启动框架服务的其他服务线程已经完成所有服务。

CountDownLatch通过使用线程数初始化计数器来工作,每次线程完成执行时,该计数器都会递减。当count达到零时,表示所有线程都已完成执行,并且线程等待锁存器恢复执行。

java并发编程之CountDownLatch_第1张图片

CountDownLatch概念

CountDownLatch的伪代码可以这样写:

//主线程开始
//为N个线程创建CountDownLatch
//创建并启动N个线程
//主线程等待锁存器
// N个线程完成任务返回
//主线程恢复执行

CountDownLatch如何工作?

CountDownLatch.java类定义了一个构造函数:

//Constructs a CountDownLatch initialized with the given count.

public CountDownLatch(int count) {...}

这个计数本质上是线程的数量,锁存器应该等待。此值只能设置一次,而CountDownLatch不提供其他机制来重置此计数

与CountDownLatch的第一次交互是主线程,即goind等待其他线程。这个主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。执行将在await()方法上停止,直到时间,其他线程完成执行。

其他N个线程必须引用latch对象,因为它们需要通知CountDownLatch对象它们已经完成了它们的任务。此通知通过以下方法完成:CountDownLatch.countDown() ; 每次调用方法都会减少构造函数中设置的初始计数,因此,当所有N个线程都调用此方法时,count将达到零,并允许主线程通过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:这个clas是主要的启动类,它启动锁存器并等待这个锁存器,直到检查完所有服务。

public class ApplicationStartupUtil

{

    //List of service checkers

    private static List _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();

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

    }

}

现在您可以编写任何测试类来检查latch的功能。

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类有哪些主要方法?

你可能感兴趣的:(java)