非主流并發(fā)工具之 CyclicBarrier
Posted on 2011-10-17 11:21 蜀山兆孨龘 閱讀(1794) 評(píng)論(0) 編輯 收藏 所屬分類: Java SECyclicBarrier
的功能類似于前面說(shuō)到的 CountDownLatch
,用于讓多個(gè)線程(子任務(wù))互相等待,直到共同到達(dá)公共屏障點(diǎn)(common barrier point),在這個(gè)點(diǎn)上,所有的子任務(wù)都已完成,從而主任務(wù)完成。
該類構(gòu)造的時(shí)候除了必須要指定線程數(shù)量,還可以傳入一個(gè) Runnable
對(duì)象,它的 run
方法將在到達(dá)公共屏障點(diǎn)后執(zhí)行一次。子線程完成計(jì)算后,分別調(diào)用 CyclicBarrier#await
方法進(jìn)入阻塞狀態(tài),直到其他所有子線程都調(diào)用了 await
。
下面仍然以運(yùn)動(dòng)員準(zhǔn)備賽跑為例來(lái)說(shuō)明 CyclicBarrier
的用法:
final int count = 8; System.out.println("運(yùn)動(dòng)員開始就位。"); final CyclicBarrier cb = new CyclicBarrier(count, new Runnable() { @Override public void run() { System.out.println("比賽開始..."); } }); for (int i = 1; i <= count; i++) { final int number = i; new Thread() { @Override public void run() { System.out.println(number + " 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備..."); try { // 準(zhǔn)備 2~5 秒鐘。 TimeUnit.SECONDS.sleep(new Random().nextInt(4) + 2); } catch (InterruptedException ex) { } System.out.println(number + " 號(hào)運(yùn)動(dòng)員就位。"); try { cb.await(); } catch (InterruptedException | BrokenBarrierException ex) { } } }.start(); } System.out.println("等待所有運(yùn)動(dòng)員就位...");
運(yùn)行輸出(可能)為:
運(yùn)動(dòng)員開始就位。 1 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備... 2 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備... 等待所有運(yùn)動(dòng)員就位... 3 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備... 4 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備... 6 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備... 8 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備... 5 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備... 7 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備... 1 號(hào)運(yùn)動(dòng)員就位。 3 號(hào)運(yùn)動(dòng)員就位。 8 號(hào)運(yùn)動(dòng)員就位。 6 號(hào)運(yùn)動(dòng)員就位。 2 號(hào)運(yùn)動(dòng)員就位。 7 號(hào)運(yùn)動(dòng)員就位。 5 號(hào)運(yùn)動(dòng)員就位。 4 號(hào)運(yùn)動(dòng)員就位。 比賽開始...
最后看看 CyclicBarrier
和 CountDownLatch
的主要異同:
- 兩者在構(gòu)造的時(shí)候都必須指定線程數(shù)量,而且該數(shù)量在構(gòu)造后不可修改。
- 前者可以傳入一個(gè)
Runnable
對(duì)象,在任務(wù)完成后自動(dòng)調(diào)用,執(zhí)行者為某個(gè)子線程;后者可在await
方法后手動(dòng)執(zhí)行一段代碼實(shí)現(xiàn)相同的功能,但執(zhí)行者為主線程。 - 前者在每個(gè)子線程上都進(jìn)行阻塞,然后一起放行;后者僅在主線程上阻塞一次。
- 前者可以重復(fù)使用;后者的倒計(jì)數(shù)器歸零后就作廢了。
- 兩者的內(nèi)部實(shí)現(xiàn)完全不同。