java多线程-CountDownLatchh和CyclicBarrier
一、CountDownLatch
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量,每当一个线程完成了自己的任务后,计数器就会减1。当计数器值到达0时,表示所有得线程已经完成了任务,然后闭锁上等待的线程就恢复执行任务
1、使用场景
1、开始执行前等待n 个线程完成各自的任务:例如应用程序启动类要确保在处理用户请求前,所有n个任务已经启动和运行了
2、死锁检测
2、方法
//构造方法
CountDownLatch latch = new CountDownLatch(int num);
//减少计数器
latch.countDown();
//主线程执行
latch.await();
3、如何使用
- 开始执行主线程
- 为N个线程创建CountDownLatch
- N个线程开始执行
- 主线程在latch处执行等待
- 主线程开始执行
4、代码实例
package java_lang_Object;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* Created by luckyboy on 2018/7/10.
*/
abstract class BaseHealthChecker implements Runnable{
private CountDownLatch latch;
private String service_Name;
private boolean serviceUp;
public BaseHealthChecker(String service_Name,CountDownLatch latch){
this.latch = latch;
this.service_Name = service_Name;
}
@Override
public void run(){
try{
//验证类是否启动
verifyService();
//启动服务置为true
serviceUp = true;
}catch (Throwable t){
t.printStackTrace();
//启动失败则值为false
serviceUp = false;
}finally{
if(latch != null){
latch.countDown();
}
}
}
public abstract void verifyService();
public String getServiceName() {
return this.service_Name;
}
public boolean isServiceUp(){
return this.serviceUp;
}
}
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");
}
}
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(3000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(this.getServiceName()+"is Up");
}
}
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(3000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(this.getServiceName()+"is Up");
}
}
工具类,只有当我们的NetworkHealthChecker、DataBaseHealthChecker、CacheHealthChecker三个类启动了以后,最终才会执行判断是否所有的类输出一个true
class ApplicationStartupUtil{
private static List<BaseHealthChecker> services;
private static CountDownLatch latch;
private ApplicationStartupUtil(){
}
private final static ApplicationStartupUtil INSTANCE = new ApplicationStartupUtil();
public static ApplicationStartupUtil getInstance(){
return INSTANCE;
}
public static void checkExternalServices(){
boolean flag = true;
latch = new CountDownLatch(3);
services = new ArrayList<BaseHealthChecker>();
services.add(new NetworkHealthChecker(latch));
services.add(new DataBaseHealthChecker(latch));
services.add(new CacheHealthChecker(latch));
Executor executorService = Executors.newFixedThreadPool(services.size());
for(final BaseHealthChecker v:services){
executorService.execute(v);
}
try {
latch.await();
for(final BaseHealthChecker v:services){
if(!v.isServiceUp()){
flag = false;
}
}
System.out.println("External services validation completed !! Result was::"+flag);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试类
public class CountDownLatchTest_II {
public static void main(String[] args){
ApplicationStartupUtil application = ApplicationStartupUtil.getInstance();
application.checkExternalServices();
}
}
输出结果
CheckingNetwork Service
CheckingDatabase Service
CheckingCache Service
Database Serviceis Up
Cache Serviceis Up
Network Serviceis Up
External services validation completed !! Result was::true
总结:
- 主线程必须在启动其他线程后立即调用CountDownLatch.await()方法,这样主喜线程就会在这个方法上阻塞,知道其他线程完成各自的任务
- 其他的N个线程必须要引用主线程中创建的CountDownLatch对象,因为他们需要调用CountDownLatch.countDown()方法来告知主线程自己完成了任务
- 每个线程执行了countDown()之后,我们的在CountDownLatch(int num)的num就会减1。知道num 减少到零,此时主线程就可以执行任务了
参考文章
https://howtodoinjava.com/core-java/multi-threading/threadpoolexecutor-callable-future-example/
http://www.importnew.com/15731.html
https://blog.youkuaiyun.com/zzg1229059735/article/details/61191679