/*
* 循环屏障
* 由分支线程主导任务执行
* 例:五人相约吃饭(1、2、3、4、5,5个线程,最后到的负责叫服务员点餐),因为各走各的(步行的、开车的、坐地铁的等),所以到达饭店有先有后
* 第一次
* 假设2先到,发现自己不是最后一个人,所以等待,
* 然后3也到了,也发现自己不是最后一个,所以等待,
* 这时4在来的路上突然临时有事,去不了了,就通知其它人,下次再聚
* 其他人收到通知到了的就回家,没到的也不会再去,也会回家
* 第二次
* 哥五个商量好了,第二天再次聚餐
* 这次,假设1、3、4都已经到饭店了在等2和5
* 在等的过程中,4突然接到电话有事,不能吃饭了,则通知其它人,下次再聚
* 这时1和3就会被告知别等了不能吃了回家吧,2和5没来在路上也会收到通知直接回家
* 第三次吃饭
* 这次假设1、4、5都到了在等待,4来的时候就告诉了,我今天还有事哈就能等半个小时,
* 半个小时人没到齐我还得走
* 结果时间到了,3来了2还没到,
* 完又吃不成了,叫醒等睡着的1、3、5通知2也不用来了都回家吧。
* 第四次吃饭
* 这次假设1、2、3、5都分别到达了吃饭的地,谁今天都没事,都等最后一个到了就吃饭
* 4这时候到了,发现自己最后一个到的,于是就叫服务员点餐吃饭
* 吃饭吃的挺好,也没出别的事
* 吃饭完哥几个相约过几天接着约哈。
*/
public class CyclicBarrier {
/*
* 每次饭局破坏情况
*/
private static class Generation {
//false饭局未被破坏,true饭局遭到破坏
boolean broken = false;
}
/*
* 饭店大门一次只能进一个人
* 进去的人在里面落座了或者出来了才能进下一个
*/
private final ReentrantLock lock = new ReentrantLock();
/*
* 饭店休息室,可大可小的休息室,反正几个人都能容下,先到的都在这等着
*/
private final Condition trip = lock.newCondition();
/*
* 吃饭人数
*/
private final int parties;
/*
* 最后一个到场的人要负责的事
*/
private final Runnable barrierCommand;
/*
* 每次饭局破坏情况
*/
private Generation generation = new Generation();
/*
* 统计未到场人数
*/
private int count;
/*
* 吃好了,相约下次再聚
*/
private void nextGeneration() {
trip.signalAll();
count = parties;
generation = new Generation();
}
/*
* 饭局遭受破坏,到场的人都散了吧
* 未到场人数设置为全员
*/
private void breakBarrier() {
generation.broken = true;
count = parties;
trip.signalAll();
}
/*
* 一个一个进饭店
* 先到的先到休息室等人,
* 最后一个到的叫服务员点餐,同时通知所有在休息室的人到包间吃饭
* 人齐吃饭,吃完吃好相约下次再聚
* 人在到齐的过程中,有一人有事未到则取消饭局
* 人在到齐的过程中,到的人中有一人有事离开,饭局取消
* 人在到齐的过程中,到的人中,有一人等时间长了,不等离开了,饭局取消
* 在吃饭的过程中没吃好,谈合同没谈好,饭局取消
*/
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
int index = --count;
//最后一个到场的,叫服务员点餐,通知所有等待的人吃饭
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// 先到场的进去等
// 临时有事的,等不及的就走,
//走的时候通知其它等待的人也走
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
/*
* 形成吃饭这件事的共识,并约定几个人吃,最后到的人负责通知服务员点餐
*/
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
/*
* 形成吃饭这件事的共识,并约定几个人吃,自助餐,不用叫服务员点餐
*/
public CyclicBarrier(int parties) {
this(parties, null);
}
/*
* 获取吃饭人数
*/
public int getParties() {
return parties;
}
/*
* 吃饭的人没有其它预约,所以不设置到场等待时间
*/
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
/*
* 吃饭的人有其它预约,到时间就得走
*/
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
/*
* 获取饭局是否被破坏
*/
public boolean isBroken() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return generation.broken;
} finally {
lock.unlock();
}
}
/*
* 重置饭局
*/
public void reset() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
breakBarrier(); // break the current generation
nextGeneration(); // start a new generation
} finally {
lock.unlock();
}
}
/*
* 获取到场人数
*/
public int getNumberWaiting() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return parties - count;
} finally {
lock.unlock();
}
}
}
CyclicBarrier与CountDownLatch比较
CyclicBarrier是由分线程主导,分线程最后一个去执行一项任务,执行完后唤醒其它线程继续执行。不存在另外一个不同类的线程等待。
CountDownLatch是有一个线程在等待其它线程执行,其它线程中的最后一个执行完去唤醒这个等待的线程继续执行。存在一个不同类的线程等待。
CountDownLatch举例:下班的班车司机等全员到齐出发
司机是一个线程他在等全员到齐,所有员工是其它线程,最后一个上车的员工通知司机我是最后一个,人齐了可以出发了。司机收到讯息后启动班车出发。
以上如有不足望或错误望指正。