C++中 NULL 和 nullptr 區別
所有的執行緒必須同時到達柵欄位置,才能繼續執行。柵欄用於等待其他執行緒。
CyclicBarrier可以使一定數量的執行緒反覆地在柵欄位置處彙集。當執行緒到達柵欄位置時將呼叫await方法,這個方法將阻塞直到所有執行緒都到達柵欄位置。如果所有執行緒都到達柵欄位置,那麼柵欄將開啟,此時所有的執行緒都將被釋放,而柵欄將被重置以便下次使用。
CyclicBarrier預設的構造方法是CyclicBarrier(int parties),其引數表示屏障攔截的執行緒數量,每個執行緒使用await()方法告訴CyclicBarrier我已經到達了屏障,然後當前執行緒被阻塞。
CyclicBarrier的另一個建構函式CyclicBarrier(int parties, Runnable barrierAction),用於執行緒到達屏障時,優先執行barrierAction,方便處理更復雜的業務場景。
以上內容參考:https://blog.csdn.net/qq_38293564/article/details/80558157
demo:
public class CycleBarrierTest { public static void main(String[] args) { CyclicBarrier cb = new CyclicBarrier(3); for (int i = 0; i < 3; i++) { System.out.println("建立工作執行緒" + i); Thread t = new Thread(new Worker(cb)); t.start(); } } static class Worker implements Runnable { private CyclicBarrier cb; public Worker(CyclicBarrier cb){ this.cb = cb; } @Override public void run() { try { System.out.println(Thread.currentThread().getName() + "開始等待其他執行緒..."); cb.await(); System.out.println(Thread.currentThread().getName() + "執行完成..."); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } }
原始碼分析:
CyclicBarrier的await()方法
/** * Main barrier code, covering the various policies. */ 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(); // 如果執行緒中斷,則喚醒所有執行緒, 重置代和count if (Thread.interrupted()) { breakBarrier(); throw new InterruptedException(); } int index = --count; // 當index ==0 的時候,則為最後一個執行緒呼叫該方法。 if (index == 0) { // tripped // 損壞狀態識別符號 boolean ranAction = false; try { final Runnable command = barrierCommand; // 執行建構函式為CyclicBarrier(int parties, Runnable barrierAction)的barrierAction的run方法 if (command != null) command.run(); ranAction = true; // 喚醒所有執行緒, 重置代和count nextGeneration(); return 0; } finally { if (!ranAction) breakBarrier(); } } // loop until tripped, broken, interrupted, or timed out 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 { // We're about to finish waiting even if we had not // been interrupted, so this interrupt is deemed to // "belong" to subsequent execution. Thread.currentThread().interrupt(); } } // 如果代損壞了丟擲異常 if (g.broken) throw new BrokenBarrierException(); // 如果不是當前代,就返回下標 // 因為一個執行緒可以使用多個柵欄,所以需要代來區分。 if (g != generation) return index; // 如果有時間限制且小於0,則喚醒所有執行緒, 重置代和count並丟擲異常 if (timed && nanos <= 0L) { breakBarrier(); throw new TimeoutException(); } } } finally { lock.unlock(); } }
在CyclicBarrier中,同一批執行緒屬於同一代。當有parties個執行緒到達barrier之後,generation就會被更新換代。其中broken標識該當前CyclicBarrier是否已經處於中斷狀態。
CountDownLatch一般用於某個執行緒A等待若干其他執行緒完成後,它才執行; 而CyclicBarrier一般用於一組執行緒互相等待至某個狀態,然後一組執行緒再同時執行。
CountDownLatch強調一個執行緒等多個執行緒完成某件事情;CyclicBarrier是多個執行緒互等,等大家完成,再攜手共進。
