概述
用来进行线程同步协作,等待所有线程完成倒计时。其中构造参数用来初始化等待计数值,await() 用来等待计数归零,countDown() 用来让计数减一
案例
案例1 ```java
public static void test1() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);new Thread(() -> {log.info("begin...");sleep(1);latch.countDown();log.info("end...{}", latch.getCount());}).start();new Thread(() -> {log.info("begin...");sleep(2);latch.countDown();log.info("end...{}", latch.getCount());}).start();new Thread(() -> {log.info("begin...");sleep(1.5);latch.countDown();log.info("end...{}", latch.getCount());}).start();log.info("waiting...");//等待计数归零latch.await();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
- 案例2配合线程池使用```javaprivate static void test5() {CountDownLatch latch = new CountDownLatch(3);ExecutorService service = Executors.newFixedThreadPool(4);service.submit(() -> {log.debug("begin...");sleep(1);latch.countDown();log.debug("end...{}", latch.getCount());});service.submit(() -> {log.debug("begin...");sleep(1.5);latch.countDown();log.debug("end...{}", latch.getCount());});service.submit(() -> {log.debug("begin...");sleep(2);latch.countDown();log.debug("end...{}", latch.getCount());});service.submit(()->{try {log.debug("waiting...");//等待前面三个线程执行结束后再执行latch.await();log.debug("wait end...");} catch (InterruptedException e) {e.printStackTrace();}});}2021-10-04 22:13:15.063 [pool-1-thread-1] DEBUG- begin...2021-10-04 22:13:15.063 [pool-1-thread-2] DEBUG- begin...//线程4比线程3先启动,但是在等待2021-10-04 22:13:15.063 [pool-1-thread-4] DEBUG- waiting...2021-10-04 22:13:15.063 [pool-1-thread-3] DEBUG- begin...2021-10-04 22:13:16.066 [pool-1-thread-1] DEBUG- end...22021-10-04 22:13:16.566 [pool-1-thread-2] DEBUG- end...12021-10-04 22:13:17.066 [pool-1-thread-3] DEBUG- end...0//前面的线程执行完毕,线程4继续执行2021-10-04 22:13:17.066 [pool-1-thread-4] DEBUG- wait end...
- 案例3
模拟游戏加载进度,所有的游戏玩家都加载到100%,游戏才能开始
private static void test2() throws InterruptedException {AtomicInteger num = new AtomicInteger(0);// 设置线程工厂,目的是给线程起名字ExecutorService service = Executors.newFixedThreadPool(10, (r) -> {return new Thread(r, "t" + num.getAndIncrement());});//指定10个玩家CountDownLatch latch = new CountDownLatch(10);String[] all = new String[10];Random r = new Random();for (int j = 0; j < 10; j++) {int x = j;service.submit(() -> {for (int i = 0; i <= 100; i++) {try {//随机睡眠,模拟网速Thread.sleep(r.nextInt(100));} catch (InterruptedException e) {}//统计加载进度all[x] = Thread.currentThread().getName() + "(" + (i + "%") + ")";//覆盖上一次的打印结果System.out.print("\r" + Arrays.toString(all));}latch.countDown();});}//等待所有玩家加载完成latch.await();System.out.println("\n游戏开始...");service.shutdown();}


- 案例4
在分布式开发中,有时一个请求需要等待多个微服务的返回后才能继续执行
解决办法
- 使用串行调用方式,但是这种方式效率比较低,花费的时间是所有请求时间的和
使用线程池提交任务,每个任务处理一个微服务的请求。但是需要保证在最后一个请求调用 之前,其他请求已经处理完成。所以可以使用到
CountDownLatchprivate static void test4() throws InterruptedException {RestTemplate restTemplate = new RestTemplate();log.info("begin");ExecutorService service = Executors.newCachedThreadPool();CountDownLatch latch = new CountDownLatch(4);service.submit(() -> {Map<String, Object> response = restTemplate.getForObject("http://localhost:8011/order/{1}", Map.class, 1);log.info("{}", response);latch.countDown();});service.submit(() -> {Map<String, Object> response = restTemplate.getForObject("http://localhost:8011/product/{1}", Map.class, 1);log.info("{}", response);latch.countDown();});service.submit(() -> {Map<String, Object> response = restTemplate.getForObject("http://localhost:8011/product/{1}", Map.class, 2);log.info("{}", response);latch.countDown();});service.submit(() -> {Map<String, Object> response =restTemplate.getForObject("http://localhost:8011/logistics/{1}", Map.class, 1);log.info("{}", response);latch.countDown();});latch.await();log.info("执行完毕");service.shutdown();}
