CyclicBarrier类简介
CyclicBarrier作用
CyclicBarrier是java.util.concurrent包下的一个类,是一个可以循环使用(Cylcic)的屏障(Barrier)。作用就是让一组线程到达一个屏障(同步点)时被阻塞,直到这组线程中的最后一个到达屏障时,屏障才会打开,之前阻塞的线程继续运行。过程如下图所示:
上图中的三个线程中各有一个barrier.await,任何一个线程在运行到barrier.await时都会进入阻塞等待状态,直到三个线程都到了barrier.await时才从await返回,三个线程同时继续地向后运行。通过它可以实现让一组线程等待至某个状态之后再全部同时执行,叫做“循环”是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。
主要方法
CyclicBarrier的使用
效果演示
@Slf4j(topic = "c.CyclicBarrierTest")
public class CyclicBarrierTest {
public static void main(String[] args) {
// 个数为2时才会继续执行
CyclicBarrier cb = new CyclicBarrier(2, () -> {
log.debug("兄弟们,准备好出发了吗");
});
new Thread(() -> {
log.debug("线程1开始.." + new Date());
try {
cb.await(); // 当个数不足时,等待
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
log.debug("线程1继续向下运行..." + new Date());
}).start();
new Thread(() -> {
log.debug("线程2开始.." + new Date());
try {
Thread.sleep(2000);
} catch (InterruptedException ignored) {
}
try {
cb.await(); // 2 秒后,线程个数够2,继续运行
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
log.debug("线程2继续向下运行..." + new Date());
}).start();
}
}
运行结果:
可以看到,在每个线程都调用await方法前,全部线程都被阻塞了,只要都调用到了await方法,全部线程才会一起继续执行。
CyclicBarrier使用时的注意事项
- 如果在线程池中使用,一定要确保线程池的线程数量大于等于CyclicBarrier对象的规定阻塞线程数量,否则可能会导致到达栅栏的线程不足而无法“放行”的情况
调用await()方法的次数一定要等于屏障中设置的阻塞线程的数量,否则会死锁
CyclicBarrier和CountDownLatch的区别
二者都能让一个或多个线程阻塞等待,都可以用在多个线程间的协调,起到线程同步的作用。但CountDownLatch是多个线程都进行了countDown之后才会触发时间,唤醒await在latch上的线程,执行完countDown操作之后会继续自己线程的工作。而CyclicBarrier是一个栅栏,用于同步所有调用await方法的线程,等到所有的线程都执行了await方法后,所有的线程才会返回各自执行自己的工作。
- CountDownLatch计数器只能使用一次,而CyclicBarrier的计数器可以调用 reset() 方法重置,能处理更加复杂的业务场景。