[关闭]
@boothsun 2018-03-06T12:03:37.000000Z 字数 3386 阅读 1143

CountDownLatch学习

Java多线程


参考原文
1. 什么时候使用CountDownLatch

CountDownLatch是什么

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

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

CountDownLatch 常用API

构造方法:

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

常用方法:

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

应用场景

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

  1. import java.util.Arrays;
  2. import java.util.List;
  3. import java.util.concurrent.CountDownLatch;
  4. import java.util.concurrent.Executor;
  5. import java.util.concurrent.Executors;
  6. /**
  7. * 模拟程序启动时 相关环境检查
  8. */
  9. public class CountDownLatchTest {
  10. public static void main(String[] args) {
  11. try {
  12. Boolean result = ApplicationStartupUtil.checkExtenalServoce();
  13. if(result) {
  14. System.out.println("健康检查全部健康");
  15. } else {
  16. throw new RuntimeException("程序依赖环境不健康");
  17. }
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }
  23. abstract class BaseHealthChecker implements Runnable {
  24. private CountDownLatch countDownLatch ;
  25. protected boolean isHealth ;
  26. private String serviceName ;
  27. public BaseHealthChecker(String serviceName , CountDownLatch countDownLatch) {
  28. this.countDownLatch = countDownLatch;
  29. this.serviceName = serviceName ;
  30. isHealth = false ;
  31. }
  32. @Override
  33. public void run() {
  34. try {
  35. this.verifyService();
  36. isHealth = true ;
  37. }catch (Exception e) {
  38. e.printStackTrace();
  39. isHealth = false ;
  40. } finally {
  41. if(countDownLatch != null) {
  42. countDownLatch.countDown();
  43. }
  44. }
  45. }
  46. abstract void verifyService() ;
  47. public boolean isHealth() {
  48. return isHealth;
  49. }
  50. public String getServiceName() {
  51. return serviceName;
  52. }
  53. }
  54. class NetWorkHealthChecker extends BaseHealthChecker {
  55. public NetWorkHealthChecker( CountDownLatch countDownLatch) {
  56. super( "NetWorkHealthChecker" , countDownLatch ) ;
  57. }
  58. @Override
  59. void verifyService() {
  60. System.out.println("starting Checking " + this.getServiceName());
  61. try {
  62. Thread.sleep(2000);
  63. } catch (InterruptedException e) {
  64. e.printStackTrace();
  65. }
  66. System.out.println( this.getServiceName() + " is Health");
  67. isHealth = true ;
  68. }
  69. }
  70. class DatabaseHealthChecker extends BaseHealthChecker {
  71. public DatabaseHealthChecker( CountDownLatch countDownLatch) {
  72. super( "DatabaseHealthChecker" , countDownLatch ) ;
  73. }
  74. @Override
  75. void verifyService() {
  76. System.out.println("starting Checking " + this.getServiceName());
  77. try {
  78. Thread.sleep(1000);
  79. } catch (InterruptedException e) {
  80. e.printStackTrace();
  81. }
  82. System.out.println( this.getServiceName() + " is Health");
  83. isHealth = true ;
  84. }
  85. }
  86. class ApplicationStartupUtil {
  87. private static List<BaseHealthChecker> healthCheckerList ;
  88. private static CountDownLatch countDownLatch ;
  89. private ApplicationStartupUtil() {
  90. }
  91. public static boolean checkExtenalServoce() throws Exception {
  92. countDownLatch = new CountDownLatch(2) ;
  93. healthCheckerList = Arrays.asList(new DatabaseHealthChecker(countDownLatch) , new NetWorkHealthChecker(countDownLatch)) ;
  94. Executor executor = Executors.newFixedThreadPool(healthCheckerList.size()) ;
  95. healthCheckerList.forEach((num)-> executor.execute(num));
  96. countDownLatch.await() ;
  97. System.out.println(countDownLatch.getCount());
  98. //等待健康检查完毕
  99. healthCheckerList.forEach((num) -> {
  100. System.out.println(num.isHealth);
  101. if(!num.isHealth()) {
  102. throw new RuntimeException(num.getServiceName() + "健康检查失败");
  103. }
  104. });
  105. return true ;
  106. }
  107. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注