CountDownLatch学习

参考原文

  1. 什么时候使用CountDownLatch

CountDownLatch是什么

CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。
单词Latch的中文翻译是门闩,也就是有“门锁”的功能,所以当门没有打开时,N个人是不能进入屋内的,也就是N个线程是不能继续往下运行的,支持这样的特性可以控制线程执行任务的时机

CountDownLatch是通过一个计数器来实现的,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务了。

CountDownLatch 常用API

构造方法:

public CountDown(int count){} 
//count初始化计数值,一旦count初始化完成后,就不可重新初始化或者修改CountDownLatch对象的内部计数器的值。 

常用方法:

public void await() {}; //使当前线程挂起,直到计数值为0时,才继续往下执行。
public boolean await(long timeout , TimeUnit timeUnit) throws InterruptExcetion {};
public void  countDown() {} //将count值减1

应用场景

CountDownLatch的一个非常典型的应用场景就是:有一个任务想要往下执行,但必须等到其他多个任务执行(如果是单个任务 顺序执行就好了)完毕后才进行继续往下执行。此时,我们可以在这个等待其他任务的线程里调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。


import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * 模拟程序启动时 相关环境检查
 */
public class CountDownLatchTest {
    public static void main(String[] args) {
        try {
            Boolean result = ApplicationStartupUtil.checkExtenalServoce();
            if(result) {
                System.out.println("健康检查全部健康");
            } else {
                throw new RuntimeException("程序依赖环境不健康");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

abstract class BaseHealthChecker implements Runnable {

    private CountDownLatch countDownLatch ;

    protected boolean isHealth ;

    private String serviceName ;

    public BaseHealthChecker(String serviceName , CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
        this.serviceName = serviceName ;
        isHealth = false ;
    }

    @Override
    public void run() {
        try {
            this.verifyService();
            isHealth = true ;
        }catch (Exception e) {
            e.printStackTrace();
            isHealth = false ;
        } finally {
            if(countDownLatch != null) {
                countDownLatch.countDown();
            }
        }
    }

    abstract void verifyService() ;

    public boolean isHealth() {
        return isHealth;
    }

    public String getServiceName() {
        return serviceName;
    }
}


class NetWorkHealthChecker extends BaseHealthChecker {

    public NetWorkHealthChecker( CountDownLatch countDownLatch) {
        super( "NetWorkHealthChecker" , countDownLatch ) ;
    }

    @Override
    void verifyService() {
        System.out.println("starting Checking " + this.getServiceName());

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println( this.getServiceName() + " is Health");
        isHealth = true ;
    }
}

class DatabaseHealthChecker extends BaseHealthChecker {

    public DatabaseHealthChecker( CountDownLatch countDownLatch) {
        super( "DatabaseHealthChecker" , countDownLatch ) ;
    }

    @Override
    void verifyService() {

        System.out.println("starting Checking " + this.getServiceName());

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println( this.getServiceName() + " is Health");
        isHealth = true ;
    }
}

class ApplicationStartupUtil {

    private static List<BaseHealthChecker> healthCheckerList ;

    private static CountDownLatch countDownLatch ;

    private ApplicationStartupUtil() {

    }

    public static boolean checkExtenalServoce() throws Exception {

        countDownLatch = new CountDownLatch(2) ;
        healthCheckerList = Arrays.asList(new DatabaseHealthChecker(countDownLatch) , new NetWorkHealthChecker(countDownLatch)) ;

        Executor executor = Executors.newFixedThreadPool(healthCheckerList.size()) ;

        healthCheckerList.forEach((num)-> executor.execute(num));

        countDownLatch.await() ;
        System.out.println(countDownLatch.getCount());

        //等待健康检查完毕
        healthCheckerList.forEach((num) -> {
            System.out.println(num.isHealth);
            if(!num.isHealth()) {
                throw new RuntimeException(num.getServiceName() + "健康检查失败");
            }
        });

        return true ;

    }
}
posted @ 2017-07-14 09:38  做个有梦想的咸鱼  阅读(252)  评论(0编辑  收藏  举报