CountDownLatch 原理
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
构造函数
//Constructs a CountDownLatch initialized with the given count.
public CountDownLatch(int count) {...}
CountDownLatch.await()
方法,这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务为止。CountDownLatch.countDown()
方法完成的,每次调用计数减少 1。await()
方法之后继续执行。public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
......
Sync(int count) {
setState(count);
}
阻塞线程
await 方法
acquireSharedInterruptibly()
。
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
......
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
tryAcquireShared 方法
countDown()
函数都会减 1。protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
doAcquireSharedInterruptibly()
。释放操作
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
......
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
await()
阻塞的线程接着调用 doReleaseShared()
唤醒。限定时间的 await
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
doAcquireSharedNanos()
方法,不同之处只是加了时间的处理。实现最大的并行性
countDown()
方法就可以让其他所有等待的线程同时恢复执行。开始执行前等待 N 个线程完成各自任务
死锁检测
BaseHealthChecker
import java.util.concurrent.CountDownLatch;
public abstract class BaseHealthChecker implements Runnable {
private CountDownLatch _latch;
private String _serviceName;
private boolean _serviceUp;
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;
}
public abstract void verifyService();
}
verifyService()
方法。NetworkHealthChecker
import java.util.concurrent.CountDownLatch;
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");
}
}
DatabaseHealthChecker
import java.util.concurrent.CountDownLatch;
public class DatabaseHealthChecker extends BaseHealthChecker
{
public DatabaseHealthChecker (CountDownLatch latch)
{
super("Database Service", latch);
}
@Override
public void verifyService()
{
System.out.println("Checking " + this.getServiceName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getServiceName() + " is UP");
}
}
CacheHealthChecker
import java.util.concurrent.CountDownLatch;
public class CacheHealthChecker extends BaseHealthChecker
{
public CacheHealthChecker (CountDownLatch latch)
{
super("Cache Service", latch);
}
@Override
public void verifyService()
{
System.out.println("Checking " + this.getServiceName());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getServiceName() + " is UP");
}
}
ApplicationStartupUtil
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class ApplicationStartupUtil
{
private static List _services;
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
{
_latch = new CountDownLatch(3);
_services = new ArrayList();
_services.add(new NetworkHealthChecker(_latch));
_services.add(new CacheHealthChecker(_latch));
_services.add(new DatabaseHealthChecker(_latch));
Executor executor = Executors.newFixedThreadPool(_services.size());
for(final BaseHealthChecker v : _services)
{
executor.execute(v);
}
_latch.await();
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);
}
}
/** --- print ---
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
**/
join()
方法可以实现相同的功能,但是当使用了线程池时,则 join()
方法便无法实现,CountDownLatch 依然可以实现功能。package concurrent;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.*;
public class CountDownLatchDemo {
private final static CountDownLatch cdl=new CountDownLatch(3);
private final static Vector v=new Vector();
private final static ThreadPoolExecutor threadPool= new ThreadPoolExecutor(10, 15, 60, TimeUnit.SECONDS, new LinkedBlockingQueue());//使用线程池
private static class WriteThread extends Thread{
private final String writeThreadName;
private final int stopTime;
private final String str;
public WriteThread(String name,int time,String str)
{
this.writeThreadName=name;
this.stopTime=time;
this.str=str;
}
public void run()
{
System.out.println(writeThreadName+"开始写入工作");
try
{
Thread.sleep(stopTime);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
cdl.countDown();
v.add(str);
System.out.println(writeThreadName+"写入内容为:"+str+"。写入工作结束!");
}
}
private static class ReadThread extends Thread{
public void run()
{
System.out.println("读操作之前必须先进行写操作");
try
{
cdl.await();//该线程进行等待,直到countDown减到0,然后逐个苏醒过来。
//Thread.sleep(3000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
for(int i=0;i
https://howtodoinjava.com/java/multi-threading/when-to-use-countdownlatch-java-concurrency-example-tutorial/
https://blog.csdn.net/carson0408/article/details/79469725