CyclicBarrier

使用场景

一个线程组的线程需要等待所有线程完成任务后再继续执行下一次任务 。

让所有线程都等待完成后才会继续下一步行动。举个例子,就像生活中我们会约朋友们到某个餐厅一起吃饭,有些朋友可能会早到,有些朋友可能会晚到,但是这个餐厅规定必须等到所有人到齐之后才会让我们进去。这里的朋友们就是各个线程,餐厅就是 CyclicBarrier。

特点

  1. CyclicBarrier:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续工作。CyclicBarrier 默认的构造方法是 CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用 await 方法告诉 CyclicBarrier 当前线程已经到达了屏障,然后当前线程被阻塞。

code

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Slf4j
public class CyclicBarrierDemo {

public static void main(String[] args) throws Exception {

ExecutorService executor = Executors.newCachedThreadPool();

// 定义了一组屏障
int parties = 5;
CyclicBarrier barrier = new CyclicBarrier(parties, () -> {
log.info("线程组全部到达屏障前,会优先执行这里,callback is running");
});

for (int i = 0; i < 10; i++) {
final int threadNum = i;
Thread.sleep(1000);
executor.execute(() -> {
try {
race(barrier, threadNum);
// raceWithTime(barrier, threadNum);
} catch (Exception e) {
log.error("exception", e);
}
});
}
executor.shutdown();
}

private static void race(CyclicBarrier barrier, int threadNum) throws Exception {
Thread.sleep(1000);
log.info("{} is ready", threadNum);
// 在这里阻塞,等待组内所有的线程都执行完,来到屏障前,再一起continue执行
barrier.await();
log.info("{} 各个线程等待再一起继续工作 continue", threadNum);
}

/**
* 带超时时间,过了给定时间则不等待
*
* @param barrier
* @param threadNum
* @throws Exception
*/
private static void raceWithTime(CyclicBarrier barrier, int threadNum) throws Exception {
Thread.sleep(1000);
log.info("{} is ready", threadNum);
try {
// 带超时时间,过了给定时间则不等待
barrier.await(2000, TimeUnit.MILLISECONDS);
} catch (Exception e) {
log.warn("BarrierException", e);
}
log.info("{} continue", threadNum);
}
}