CyclicBarrier
的功能類似于前面說到的 CountDownLatch
,用于讓多個線程(子任務)互相等待,直到共同到達公共屏障點(common barrier point),在這個點上,所有的子任務都已完成,從而主任務完成。
該類構造的時候除了必須要指定線程數量,還可以傳入一個 Runnable
對象,它的 run
方法將在到達公共屏障點后執行一次。子線程完成計算后,分別調用 CyclicBarrier#await
方法進入阻塞狀態,直到其他所有子線程都調用了 await
。
下面仍然以運動員準備賽跑為例來說明 CyclicBarrier
的用法:
final int count = 8; System.out.println("運動員開始就位。"); 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 + " 號運動員到場并開始準備..."); try { // 準備 2~5 秒鐘。 TimeUnit.SECONDS.sleep(new Random().nextInt(4) + 2); } catch (InterruptedException ex) { } System.out.println(number + " 號運動員就位。"); try { cb.await(); } catch (InterruptedException | BrokenBarrierException ex) { } } }.start(); } System.out.println("等待所有運動員就位...");
運行輸出(可能)為:
運動員開始就位。 1 號運動員到場并開始準備... 2 號運動員到場并開始準備... 等待所有運動員就位... 3 號運動員到場并開始準備... 4 號運動員到場并開始準備... 6 號運動員到場并開始準備... 8 號運動員到場并開始準備... 5 號運動員到場并開始準備... 7 號運動員到場并開始準備... 1 號運動員就位。 3 號運動員就位。 8 號運動員就位。 6 號運動員就位。 2 號運動員就位。 7 號運動員就位。 5 號運動員就位。 4 號運動員就位。 比賽開始...
最后看看 CyclicBarrier
和 CountDownLatch
的主要異同:
- 兩者在構造的時候都必須指定線程數量,而且該數量在構造后不可修改。
- 前者可以傳入一個
Runnable
對象,在任務完成后自動調用,執行者為某個子線程;后者可在await
方法后手動執行一段代碼實現相同的功能,但執行者為主線程。 - 前者在每個子線程上都進行阻塞,然后一起放行;后者僅在主線程上阻塞一次。
- 前者可以重復使用;后者的倒計數器歸零后就作廢了。
- 兩者的內部實現完全不同。