CountDownLatch是一个同步辅助工具,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。CountDownLatch概念是很常见的面试问题,在Java并发,所以一定要充分理解它。在这篇文章中,我将介绍与java并发中的CountDownLatch相关的以下几点。
这篇文章中的章节:
什么是CountDownLatch?
CountDownLatch如何工作?
实时应用中可能的用法
示例应用
常见的面试问题
什么是CountDownLatch?
CountDownLatch 与JDK 1.5以及 java.util.concurrent包中的CyclicBarrier,Semaphore,ConcurrentHashMap和BlockingQueue等其他并发实用程序一起引入。此类使java线程等待,直到其他线程集完成其任务。例如,应用程序的主线程要等待,直到负责启动框架服务的其他服务线程已经完成所有服务。
CountDownLatch通过使用线程数初始化计数器来工作,每次线程完成执行时,该计数器都会递减。当count达到零时,表示所有线程都已完成执行,并且线程等待锁存器恢复执行。
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的CountDownLatch,并且等待所有线程等待锁存,这可以很容易地完成。对countDown()方法的单次调用将同时恢复所有等待线程的执行。
- 等待N个线程在开始执行之前完成:例如,应用程序启动类希望在处理用户请求之前确保所有N个外部系统都已启动并正在运行。
- 死锁检测:一个非常方便的用例,您可以在每个测试阶段使用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.java和CacheHealthChecker.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类有哪些主要方法?