为了更好的理解CyclicBarrier的应用,我们需要在现实生活中找到一个合适的场景;大家应该都有旅游的经验,景区通常都有旅游大巴,这些大巴的作用就是把旅客从游客中心运送到景点的入口;
- 首先是旅客在游客中心购买门票;
- 旅客就到大巴集散处排队上车;
- 排队人数达到了一车大巴的人数后(载客人数为2人),这些游客就上车;
- 大巴就启动出发将这一车游客载到景点;
- 继续刚才的规则……
所以我们可以把一个游客的买票排队上车抽象为一个线程;大巴启动出发抽象为另外一个线程;
/**
* CyclicBarrier
*
* @author X.T. LI
* @version V1.0
* @since 2022/7/21
*/
public class CloneablePerformance {
public static void main(String[] args) {
CyclicBarrier waitForCountTo2 = new CyclicBarrier(2, new Bus());
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 1; i < 4; i++) {
executorService.submit(new Traveler(waitForCountTo20, i));
}
}
}
@Slf4j
class Traveler implements Runnable {
CyclicBarrier waitForCountTo20;
Integer travelerNo;
public Traveler(CyclicBarrier waitForCountTo20, Integer travelerNo) {
this.waitForCountTo20 = waitForCountTo20;
this.travelerNo = travelerNo;
}
@Override
public void run() {
log.info("Buy ticket. Traveler{} buy ticket.", travelerNo);
log.info("Get on car. Traveler{} get on car.", travelerNo);
try {
waitForCountTo20.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
@Slf4j
class Bus implements Runnable {
@Override
public void run() {
log.info("Bus runs.");
}
}
运行后的结果
Buy ticket. 3-Traveler buy ticket.Thread id is 14
Buy ticket. 2-Traveler buy ticket.Thread id is 13
Buy ticket. 1-Traveler buy ticket.Thread id is 12
Bus runs.Thread id is 14
Get on car. 3-Traveler get on car. Thread id is 14
Get on car. 2-Traveler get on car. Thread id is 13
从上述输出结果可以看出:
- 上车的只有3号和2号游客,他两上车后同时将屏障重置为了2,这里正好和CyclicBarrier单词中的Cyclic对应;
- 1号游客因为买票后时第3个去排队的,所以它没能上车。需要等待下一辆车,如果此时由第4个乘客个票后来等待那么他们两就会触发一辆车;
注意我们构建循环屏障的时候使用的是CyclicBarrier#CyclicBarrier(int parties, Runnable barrierAction);这里的barrierAction是由最后一个触发屏障的线程来执行的,所以从上述运行结果可以发现3号游客的线程号和大巴开车的线程号是一样的;
构造函数
public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)
int CyclicBarrier#getParties()
return the number of parties required to trip this barrier