概述

用来进行线程同步协作,等待所有线程完成倒计时。其中构造参数用来初始化等待计数值,await() 用来等待计数归零,countDown() 用来让计数减一

案例

  • 案例1 ```java

    public static void test1() throws InterruptedException {

    1. CountDownLatch latch = new CountDownLatch(3);
    2. new Thread(() -> {
    3. log.info("begin...");
    4. sleep(1);
    5. latch.countDown();
    6. log.info("end...{}", latch.getCount());
    7. }).start();
    8. new Thread(() -> {
    9. log.info("begin...");
    10. sleep(2);
    11. latch.countDown();
    12. log.info("end...{}", latch.getCount());
    13. }).start();
    14. new Thread(() -> {
    15. log.info("begin...");
    16. sleep(1.5);
    17. latch.countDown();
    18. log.info("end...{}", latch.getCount());
    19. }).start();
    20. log.info("waiting...");
    21. //等待计数归零
    22. latch.await();
    23. log.info("wait end...");

    } //主线程启动后就等待子线程运行结束 2021-10-04 22:08:54.563 [main] INFO - waiting… 2021-10-04 22:08:54.563 [Thread-0] INFO - begin… 2021-10-04 22:08:54.563 [Thread-1] INFO - begin… 2021-10-04 22:08:54.563 [Thread-2] INFO - begin… //线程0 运行结束 2021-10-04 22:08:55.568 [Thread-0] INFO - end…2 //线程22 运行结束 2021-10-04 22:08:56.068 [Thread-2] INFO - end…1 //线程11 运行结束 2021-10-04 22:08:56.568 [Thread-1] INFO - end…0 //主线程继续运行 2021-10-04 22:08:56.568 [main] INFO - wait end…

//如果将 CountDownLatch latch = new CountDownLatch(3); 改为 CountDownLatch latch = new CountDownLatch(2); 2021-10-04 22:06:06.271 [main] INFO - waiting… 2021-10-04 22:06:06.271 [Thread-0] INFO - begin… 2021-10-04 22:06:06.271 [Thread-2] INFO - begin… 2021-10-04 22:06:06.271 [Thread-1] INFO - begin… 2021-10-04 22:06:07.274 [Thread-0] INFO - end…1 2021-10-04 22:06:07.774 [Thread-2] INFO - end…0 //此时主线程已经满足条件了 2021-10-04 22:06:07.774 [main] INFO - wait end… 2021-10-04 22:06:08.273 [Thread-1] INFO - end…0

  1. - 案例2
  2. 配合线程池使用
  3. ```java
  4. private static void test5() {
  5. CountDownLatch latch = new CountDownLatch(3);
  6. ExecutorService service = Executors.newFixedThreadPool(4);
  7. service.submit(() -> {
  8. log.debug("begin...");
  9. sleep(1);
  10. latch.countDown();
  11. log.debug("end...{}", latch.getCount());
  12. });
  13. service.submit(() -> {
  14. log.debug("begin...");
  15. sleep(1.5);
  16. latch.countDown();
  17. log.debug("end...{}", latch.getCount());
  18. });
  19. service.submit(() -> {
  20. log.debug("begin...");
  21. sleep(2);
  22. latch.countDown();
  23. log.debug("end...{}", latch.getCount());
  24. });
  25. service.submit(()->{
  26. try {
  27. log.debug("waiting...");
  28. //等待前面三个线程执行结束后再执行
  29. latch.await();
  30. log.debug("wait end...");
  31. } catch (InterruptedException e) {
  32. e.printStackTrace();
  33. }
  34. });
  35. }
  36. 2021-10-04 22:13:15.063 [pool-1-thread-1] DEBUG- begin...
  37. 2021-10-04 22:13:15.063 [pool-1-thread-2] DEBUG- begin...
  38. //线程4比线程3先启动,但是在等待
  39. 2021-10-04 22:13:15.063 [pool-1-thread-4] DEBUG- waiting...
  40. 2021-10-04 22:13:15.063 [pool-1-thread-3] DEBUG- begin...
  41. 2021-10-04 22:13:16.066 [pool-1-thread-1] DEBUG- end...2
  42. 2021-10-04 22:13:16.566 [pool-1-thread-2] DEBUG- end...1
  43. 2021-10-04 22:13:17.066 [pool-1-thread-3] DEBUG- end...0
  44. //前面的线程执行完毕,线程4继续执行
  45. 2021-10-04 22:13:17.066 [pool-1-thread-4] DEBUG- wait end...
  • 案例3

模拟游戏加载进度,所有的游戏玩家都加载到100%,游戏才能开始

  1. private static void test2() throws InterruptedException {
  2. AtomicInteger num = new AtomicInteger(0);
  3. // 设置线程工厂,目的是给线程起名字
  4. ExecutorService service = Executors.newFixedThreadPool(10, (r) -> {
  5. return new Thread(r, "t" + num.getAndIncrement());
  6. });
  7. //指定10个玩家
  8. CountDownLatch latch = new CountDownLatch(10);
  9. String[] all = new String[10];
  10. Random r = new Random();
  11. for (int j = 0; j < 10; j++) {
  12. int x = j;
  13. service.submit(() -> {
  14. for (int i = 0; i <= 100; i++) {
  15. try {
  16. //随机睡眠,模拟网速
  17. Thread.sleep(r.nextInt(100));
  18. } catch (InterruptedException e) {
  19. }
  20. //统计加载进度
  21. all[x] = Thread.currentThread().getName() + "(" + (i + "%") + ")";
  22. //覆盖上一次的打印结果
  23. System.out.print("\r" + Arrays.toString(all));
  24. }
  25. latch.countDown();
  26. });
  27. }
  28. //等待所有玩家加载完成
  29. latch.await();
  30. System.out.println("\n游戏开始...");
  31. service.shutdown();
  32. }

image.png
image.png

  • 案例4

在分布式开发中,有时一个请求需要等待多个微服务的返回后才能继续执行

  • 解决办法

    1. 使用串行调用方式,但是这种方式效率比较低,花费的时间是所有请求时间的和
    2. 使用线程池提交任务,每个任务处理一个微服务的请求。但是需要保证在最后一个请求调用 之前,其他请求已经处理完成。所以可以使用到CountDownLatch

      1. private static void test4() throws InterruptedException {
      2. RestTemplate restTemplate = new RestTemplate();
      3. log.info("begin");
      4. ExecutorService service = Executors.newCachedThreadPool();
      5. CountDownLatch latch = new CountDownLatch(4);
      6. service.submit(() -> {
      7. Map<String, Object> response = restTemplate.getForObject("http://localhost:8011/order/{1}", Map.class, 1);
      8. log.info("{}", response);
      9. latch.countDown();
      10. });
      11. service.submit(() -> {
      12. Map<String, Object> response = restTemplate.getForObject("http://localhost:8011/product/{1}", Map.class, 1);
      13. log.info("{}", response);
      14. latch.countDown();
      15. });
      16. service.submit(() -> {
      17. Map<String, Object> response = restTemplate.getForObject("http://localhost:8011/product/{1}", Map.class, 2);
      18. log.info("{}", response);
      19. latch.countDown();
      20. });
      21. service.submit(() -> {
      22. Map<String, Object> response =
      23. restTemplate.getForObject("http://localhost:8011/logistics/{1}", Map.class, 1);
      24. log.info("{}", response);
      25. latch.countDown();
      26. });
      27. latch.await();
      28. log.info("执行完毕");
      29. service.shutdown();
      30. }