【悲观锁】Synchronized和ReentrantLock的区别
【线程方法】多线程下 wait、notify、park、unpark 和 await、signal 的区别
【同步工具】CyclicBarrier和CountDownLatch的区别
CountDownLatch(倒计时)是Java并发包(java.util.concurrent)中的一个同步工具,用于控制一个或多个线程等待其他线程完成操作后再执行。它是一种多线程协作的机制,允许一个或多个线程等待其他线程的信号。
主要特点:
-
初始化计数器: 在创建CountDownLatch时,需要指定一个初始计数值。这个计数值表示需要等待完成的线程数量。
-
减少计数: 每当一个线程完成了需要等待的操作,都会调用
countDown()
方法来减少计数器的值。 -
等待计数归零: 其他线程可以通过调用
await()
方法来等待计数器归零。如果计数器为零,该方法会立即返回;否则,线程会被阻塞,直到计数器变为零。
使用示例:
下面是一个简单的Java代码示例,演示了CountDownLatch的基本用法:
private static void test4() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
new Thread(() -> {
log.debug("begin...");
sleep(1);
latch.countDown();
log.debug("end...{}", latch.getCount());
}).start();
new Thread(() -> {
log.debug("begin...");
sleep(2);
latch.countDown();
log.debug("end...{}", latch.getCount());
}).start();
new Thread(() -> {
log.debug("begin...");
sleep(1.5);
latch.countDown();
log.debug("end...{}", latch.getCount());
}).start();
log.debug("waiting...");
latch.await();
log.debug("wait end...");
}
11:38:52.854 c.TestCountDownLatch [main] - waiting...
11:38:52.854 c.TestCountDownLatch [Thread-1] - begin...
11:38:52.854 c.TestCountDownLatch [Thread-2] - begin...
11:38:52.854 c.TestCountDownLatch [Thread-0] - begin...
11:38:53.865 c.TestCountDownLatch [Thread-0] - end...2
11:38:54.358 c.TestCountDownLatch [Thread-2] - end...1
11:38:54.863 c.TestCountDownLatch [main] - wait end...
11:38:54.863 c.TestCountDownLatch [Thread-1] - end...0
结合线程池演示:
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();
}
});
}
12:46:54.982 c.TestCountDownLatch [pool-1-thread-4] - waiting...
12:46:54.982 c.TestCountDownLatch [pool-1-thread-2] - begin...
12:46:54.982 c.TestCountDownLatch [pool-1-thread-3] - begin...
12:46:54.982 c.TestCountDownLatch [pool-1-thread-1] - begin...
12:46:55.992 c.TestCountDownLatch [pool-1-thread-1] - end...2
12:46:56.498 c.TestCountDownLatch [pool-1-thread-2] - end...1
12:46:56.988 c.TestCountDownLatch [pool-1-thread-3] - end...0
12:46:56.988 c.TestCountDownLatch [pool-1-thread-4] - wait end...
等待多个远程调用完毕(在这里不演示countDownLatch,使用future接收):
private static void test3() throws InterruptedException, ExecutionException {
RestTemplate restTemplate = new RestTemplate();
log.debug("begin");
ExecutorService service = Executors.newCachedThreadPool();
CountDownLatch latch = new CountDownLatch(4);
Future<Map<String,Object>> f1 = service.submit(() -> {
Map<String, Object> response = restTemplate.getForObject("http://localhost:8080/order/{1}", Map.class, 1);
return response;
});
Future<Map<String, Object>> f2 = service.submit(() -> {
Map<String, Object> response1 = restTemplate.getForObject("http://localhost:8080/product/{1}", Map.class, 1);
return response1;
});
Future<Map<String, Object>> f3 = service.submit(() -> {
Map<String, Object> response1 = restTemplate.getForObject("http://localhost:8080/product/{1}", Map.class, 2);
return response1;
});
Future<Map<String, Object>> f4 = service.submit(() -> {
Map<String, Object> response3 = restTemplate.getForObject("http://localhost:8080/logistics/{1}", Map.class, 1);
return response3;
});
System.out.println(f1.get());
System.out.println(f2.get());
System.out.println(f3.get());
System.out.println(f4.get());
log.debug("执行完毕");
service.shutdown();
}