前言:
本文是基于《Java多线程编程实战指南-核心篇》第五章个人理解,源码是摘抄作者的源码,源码会加上自己的理解。读书笔记目前笔者正在更新如下, 《Java多线程编程实战指南-核心篇》,《How Tomcat Works》,再到《spring 源码》解读。
CountDownLatch:
CountDownLatch可以用来实现一个(或者多个)线程等待其他线程完成一组特定的操作之后才继续运行。这组操作被称为先决操作。countDownLatch内部会维护一个用户未完成的先决操作熟练的计数器,当CountDownLatch.countDown()每被执行一次就会相应实例的计数器值减少1.而CountDownLatch.await()相当于一个受保护方法,其保护条件为“计数器值为0”,因此计数器值不为0时,执行线程会被暂停,而countDown()相当于一个通知方法,在计数器值达到0时唤醒相应实例上的所有等待线程。
其中有一点,当计数器的值为0之后,该计数器的值就不再发生变化,此时再次调用countDown()并不会导致异常的抛出,并且await的线程也不会暂停,因此countDownLatch的使用是一次性的,一个countDownLatch实例只能够实现一次等待和唤醒。
实战案例:
书本里介绍了一个web服务器实战案例,其启动时需要启动若干启动过程比较耗时的服务,为了尽可能减少服务器启动过程耗时,该服务器会使用专门的工作线程以并发的方式去启动服务,但是服务器在所有启动操作结束后,需要判断这些服务的状态以检查服务器的启动是否成功,只有所有服务启动成功情况下该服务器才被认为是启动成功的。
个人觉得这个web服务器器例子很好。
代码基本讲解:
1.ServiceStarter的main是主要流程,启动所有服务->检测所有服务->最后判断输出是否启动成功。
2.启动所有服务:封装在serviceManager的startServices中,实例化了一个CountDownLatch,并且实例化了A,BC三个服务。
3.A,B,C三个服务分别继承了AbstractService,而AbstractService同时实现了接口service。
其中AbstractService为子类预留了doStart函数由子类自行实现其业务内容,所以A,B,C继承AbstractService重写doStart。 同时子类A,B,C能调用父类AnstractService的start,stop,isStart进行线程启动/停止/检查。
4.检测所有服务:封装在serviceManager的checkServiceStatus的中,进行CountDownLatch.await(),等待所有线程都启动完毕,让标志位allIsOK=true
5.最后根据标志为allIsOK输出对应的日志。
代码:
public class CaseRunner5_2 {
public static void main(String[] args) {
ServerStarter.main(args);
}
}
public class ServerStarter {
public static void main(String[] args) {
// 省略其他代码
// 启动所有服务
ServiceManager.startServices();
// 执行其他操作
// 在所有其他操作执行结束后,检测服务启动状态
boolean allIsOK;
// 检测全部服务的启动状态
allIsOK = ServiceManager.checkServiceStatus();
if (allIsOK) {
System.out.println("All services were sucessfully started!");
// 省略其他代码
} else {
// 个别服务启动失败,退出JVM
System.err.println("Some service(s) failed to start,exiting JVM...");
System.exit(1);
}
// ...
}
}
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
public class ServiceManager {
static volatile CountDownLatch latch;
static Set<Service> services;
public static void startServices() {
services = getServices();
for (Service service : services) {
service.start();
}
}
public static boolean checkServiceStatus() {
boolean allIsOK = true;
// 等待服务启动结束
try {
latch.await();
} catch (InterruptedException e) {
return false;
}
for (Service service : services) {
if (!service.isStarted()) {
allIsOK = false;
break;
}
}
return allIsOK;
}
static Set<Service> getServices() {
// 模拟实际代码
latch = new CountDownLatch(3);
HashSet<Service> servcies = new HashSet<Service>();
servcies.add(new SampleServiceC(latch));
servcies.add(new SampleServiceA(latch));
servcies.add(new SampleServiceB(latch));
return servcies;
}
}
public interface Service {
void start();
void stop();
boolean isStarted();
}
import java.util.concurrent.CountDownLatch;
public abstract class AbstractService implements Service {
protected boolean started = false;
protected final CountDownLatch latch;
public AbstractService(CountDownLatch latch) {
this.latch = latch;
}
@Override
public boolean isStarted() {
return started;
}
// 留给子类实现的抽象方法,用于实现服务器的启动逻辑
protected abstract void doStart() throws Exception;
@Override
public void start() {
new ServiceStarter().start();
}
@Override
public void stop() {
// 默认什么也不做
}
class ServiceStarter extends Thread {
@Override
public void run() {
final String serviceName = AbstractService.this.getClass()
.getSimpleName();
Debug.info("Starting %s", serviceName);
try {
doStart();
started = true;
} catch (Exception e) {
e.printStackTrace();
} finally {
latch.countDown();
Debug.info("Done Starting %s", serviceName);
}
}
}
}
import java.util.concurrent.CountDownLatch;
public class SampleServiceA extends AbstractService {
public SampleServiceA(CountDownLatch latch) {
super(latch);
}
@Override
protected void doStart() throws Exception {
// 模拟实际操作耗时
Tools.randomPause(1000);
// 省略其他代码
}
}
import java.util.concurrent.CountDownLatch;
public class SampleServiceB extends AbstractService{
public SampleServiceB(CountDownLatch latch) {
super(latch);
}
@Override
public void doStart() throws Exception {
// 模拟实际操作耗时
Tools.randomPause(2000);
// 省略其他代码
}
}
import java.util.Random;
import java.util.concurrent.CountDownLatch;
public class SampleServiceC extends AbstractService {
public SampleServiceC(CountDownLatch latch) {
super(latch);
}
@Override
public void doStart() throws Exception {
// 模拟实际操作耗时
Tools.randomPause(2000);
// 省略其他代码
// 模拟服务器启动失败
final Random random = new Random();
int rand = random.nextInt(1000);
if (rand <= 500) {
throw new RuntimeException("test");
}
}
}