一、概念说明
CountDownLatch通过一个计数器来实现,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就相应的减1。当计数器到达0时,表示所有的线程都已完成任务,然后在CountDownLatch上等待的线程就可以恢复执行任务。
CyclicBarrier是一个同步辅助工具,它允许一组线程互相等待,直到所有线程都到达某个公共屏障点(barrier point),然后才能继续执行。CyclicBarrier在初始化时需要设定一个线程数量,当线程数量达到这个数量时,所有在CyclicBarrier上等待的线程才会继续执行。CyclicBarrier是一个可重复使用的屏障,也就是说,当所有线程都到达屏障点后,CyclicBarrier会被重置,以便再次使用。
二、异同点
CountDownLatch和CyclicBarrier的相同点是:都可以实现线程间的等待。
- 侧重点不同:CountDownLatch一般用于一个线程等待一组其它线程;而CyclicBarrier一般是一组线程间的相互等待至某同步点。
- 重用性不同:CountDownLatch在倒数到0并且触发门闩打开后,就不能再次使用了,除非新建一个新的实例;而CyclicBarrier的计数器是可以重用的。
三、代码示例
countDownLatch
static CountDownLatch countDownLatch = new CountDownLatch(2);
private static void countDownLatch() {
System.out.println("全班同学开始考试:一共两个学生");
new Thread(() -> {
try {
Thread.sleep(2000);
ThreadUtil.safeSleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第一个同学交试卷");
countDownLatch.countDown();
}).start();
new Thread(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第二个同学交试卷");
countDownLatch.countDown();
}).start();
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("老师收齐试卷离开考场");
}
cycliBarrier
private static void cycliBarrier() {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
System.out.println("汇总1 ...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("汇总2 ...");
});
for(int i = 0;i < 3;i ++) {
new Thread(() -> {
try {
Thread.sleep((long)(Math.random() * 2000));
int randomInt = new Random().nextInt(500);
System.out.println("你 " + randomInt);
cyclicBarrier.await();
System.out.println("好 " + randomInt);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
cycliBarrier构造方式Runnable可选,执行的时机都是所有的线程到达屏障后执行Runnable的方法然后各自继续向下执行。