在并發工具類中,我們簡單了解了CyclicBarrier,接下來走讀下代碼看看其是如何實現的,代碼基于JDK1.7。
代碼走讀
重要的屬性
從上圖可以看出CyclicBarrier是基于可重入鎖的條件隊列實現的,parties代表同一代的線程數,count代表同一代等待的線程數,調用await()方法一次,count減1,直到為0。接下來看看dowait()方法(await()方法其實調用dowait()方法)。這個是CyclicBarrier最核心的方法。
dowait()方法流程
柵欄破壞,拋出異常。
線程中斷,主要看breakBarrier()方法,這個方法也很重要。
同一代等待的線程數減1.
當同一代等待的線程數為0時,首先執行barrierCommand的run()方法,注意:等待的線程沒有執行。
當同一代等待的線程數為0時,調用nextGeneration()方法。
breakBarrier()
喚醒等待的線程,即CyclicBarrier的線程中斷后,等待的線程還是要執行的。
nextGeneration()
喚醒等待的線程,即首先執行barrierCommand的run()方法,然后等待的線程執行;同時new Generation(),即產生新的一代,這里可以看出復用。
線程添加到循環隊列。
出現異常后執行喚醒等待線程繼續執行,即:超時后barrierCommand的run()方法不執行,等待線程仍然執行。
總結:CyclicBarrier基于可重入鎖的條件隊列實現的,可以復用的柵欄。
例子
public class CyclicBarrierDemo {
private static int SIZE = 5;
private static CyclicBarrier cb;
public static void main(String[] args) {
cb = new CyclicBarrier(SIZE, new Runnable() {
public void run() {
System.out.println("CyclicBarrier's parties is: " + cb.getParties());
}
});
// 新建10個任務
for (int i = 0; i < 10; i++)
new InnerThread().start();
}
static class InnerThread extends Thread {
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " wait for CyclicBarrier.");
// 將cb的參與者數量加1
cb.await();
// cb的參與者數量等于5時,才繼續往后執行
System.out.println(Thread.currentThread().getName() + " continued.");
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//執行結果
Thread-0 wait for CyclicBarrier.
Thread-1 wait for CyclicBarrier.
Thread-2 wait for CyclicBarrier.
Thread-3 wait for CyclicBarrier.
Thread-4 wait for CyclicBarrier.
CyclicBarrier's parties is: 5
Thread-5 wait for CyclicBarrier.
Thread-4 continued.
Thread-0 continued.
Thread-3 continued.
Thread-2 continued.
Thread-1 continued.
Thread-6 wait for CyclicBarrier.
Thread-7 wait for CyclicBarrier.
Thread-8 wait for CyclicBarrier.
Thread-9 wait for CyclicBarrier.
CyclicBarrier's parties is: 5
Thread-9 continued.
Thread-5 continued.
Thread-7 continued.
Thread-8 continued.
Thread-6 continued.