概述
用来进行线程同步协作,等待所有线程完成倒计时。其中构造参数用来初始化等待计数值,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
配合线程池使用
```java
private 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...2
2021-10-04 22:13:16.566 [pool-1-thread-2] DEBUG- end...1
2021-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
在分布式开发中,有时一个请求需要等待多个微服务的返回后才能继续执行
解决办法
- 使用串行调用方式,但是这种方式效率比较低,花费的时间是所有请求时间的和
使用线程池提交任务,每个任务处理一个微服务的请求。但是需要保证在最后一个请求调用 之前,其他请求已经处理完成。所以可以使用到
CountDownLatch
private 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();
}