前几天写了一个CountDownLatch使用示例,今天把CyclicBarrier的示例补上。
话说这日部门组织大家去吃大排档,有18个人。大排档的桌小,一桌只能4个人。大家工作完成时间不定,有人来的早有人来的晚,但约好所有人到齐才开吃。呃,这里假设所有人都一定会来(现实中可能有些人因为这样那样的原因去不了)。
因为18个人来齐才能开饭,我这里用CountDownLatch来对18人到的事件计数。
final CountDownLatch countDown = new CountDownLatch(18); // 18个人
并在主线程里
try {
countDown.await(); <span style="font-family: Arial, Helvetica, sans-serif;">// 等所有人到齐</span>
} catch (InterruptedException e) {
e.printStackTrace();
}
我们用一个CyclicBarrier对象表示能容下4个人的小桌人满、通知大排档老板
final CountDownLatch firstSignal = new CountDownLatch(1); // 第一桌
// 每4人一桌
final CyclicBarrier barrier = new CyclicBarrier(4, new Runnable() {
@Override
public void run() {
if (firstSignal.getCount() > 0) {
System.out.println("老板,先开一桌!");
} else {
System.out.println("老板,再开一桌!");
}
firstSignal.countDown();
}
});
每个人来的时候报个到,18个人最后2人只能他们两人一桌,barrier对象指定的规则不适用,需要reset(),这将产生一个BrokenBarrierException。
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 18; i++) {
final int idx = i + 1;
pool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(random.nextInt(3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第" + idx + "人到了");
countDown.countDown();
try {
barrier.await(); // 等这桌人满或所有人到齐。
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) { // 最后2人会产生此异常。
// e.printStackTrace();
System.out.println("你来的可真晚," + idx); // 来的晚要被抱怨
}
}
});
}
pool.shutdown();
在所有人到齐之后,显然有2人被barrier阻塞了,不能上桌需要如下处理
try {
countDown.await(); // 等所有人到齐
} catch (InterruptedException e) {
e.printStackTrace();
}
if (barrier.getNumberWaiting() != 0) {
System.out.println("老板,给最后" + barrier.getNumberWaiting() + "个人单开一桌!");
barrier.reset();
}
System.out.println("老板,我们人都到齐了,上菜吧");
程序输出如下:
第14人到了
第13人到了
第9人到了
第12人到了
老板,先开一桌!
第1人到了
第2人到了
第5人到了
第18人到了
老板,再开一桌!
第16人到了
第15人到了
第10人到了
第17人到了
老板,再开一桌!
第4人到了
第8人到了
第7人到了
第6人到了
老板,再开一桌!
第11人到了
第3人到了
老板,给最后2个人单开一桌!
老板,我们人都到齐了,上菜吧
你来的可真晚,11
你来的可真晚,3
代码下载请到我的github上:https://github.com/DowenLiu126/syncDemo