开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情
今天继续CountDownLatch 的第二种使用方式,检查死锁。
代码示例
公共抽象类 BaseHealthChecker
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();
}
线程实现类-DatabaseHealthChecker
public class DatabaseHealthChecker extends BaseHealthChecker{
public DatabaseHealthChecker(CountDownLatch latch) {
super("DatabaseHealthChecker", 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");
}
}
线程实现类-NetworkHealthChecker
public class NetworkHealthChecker extends BaseHealthChecker{
public NetworkHealthChecker( CountDownLatch latch) {
super("NetworkHealthChecker", 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");
}
}
main方法
public class ApplicationStartupUtil {
private ApplicationStartupUtil()
{
}
private final static ApplicationStartupUtil INSTANCE = new ApplicationStartupUtil();
public static ApplicationStartupUtil getInstance()
{
return INSTANCE;
}
public static boolean checkExternalServices() throws Exception
{
CountDownLatch latch = new CountDownLatch(2);
List<BaseHealthChecker> services = new ArrayList<BaseHealthChecker>();
services.add(new NetworkHealthChecker(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 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);
}
}
结果输出
Checking NetworkHealthChecker
Checking DatabaseHealthChecker
DatabaseHealthChecker is UP
NetworkHealthChecker is UP
External services validation completed !! Result was :: true
总结
CountDownLatch不能重新初始化或者修改CountDownLatch内部计数器的值。
CountDownLatch和Semaphore在使用AQS的方式上很相似,在同步状态中都是保存的是当前的计数值。
CountDownLatch的作用就是允许一个或多个线程等待其他线程完成操作,看起来有点类似join() 方法,但其提供了比 join() 更加灵活的API。
CountDownLatch可以手动控制在n个线程里调用n次countDown()方法使计数器进行减一操作,也可以在一个线程里调用n次执行减一操作。
join() 的实现原理是不停检查join线程是否存活,如果 join 线程存活则让当前线程永远等待。所以两者之间相对来说还是CountDownLatch使用起来较为灵活。