前幾天寫了一個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