循環栅欄CyclicBarrier
CyclicBarrier特别适用于并行疊代計算,每個線程負責一部分計算,然後在栅欄處等待其他線程完成,所有線程到齊後,交換資料和計算結果,再進行下一次疊代。
與CountDownLatch類似,它也有一個數字,但表示的是參與的線程個數,這個數字通過構造方法進行傳遞:
public CyclicBarrier(int parties)
它還有一個構造方法,接受一個Runnable參數,如下所示:
public CyclicBarrier(int parties, Runnable barrierAction)
這個參數表示栅欄動作,當所有線程到達栅欄後,在所有線程執行下一步動作前,運作參數中的動作,這個動作由最後一個到達栅欄的線程執行。
CyclicBarrier的主要方法就是await:
public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit) throws InterruptedException,
BrokenBarrierException, TimeoutException
await在等待其他線程到達栅欄,調用await後,表示自己已經到達,如果自己是最後一個到達的,就執行可選的指令,執行後,喚醒所有等待的線程,然後重置内部的同步計數,以循環使用。
await可以被中斷,可以限定最長等待時間,中斷或逾時後會抛出異常。需要說明的是異常BrokenBarrierException,它表示栅欄被破壞了,什麼意思呢?
在CyclicBarrier中,參與的線程是互相影響的,隻要其中一個線程在調用await時被中斷了,或者逾時了,栅欄就會被破壞。此外,如果栅欄動作抛出了異常,栅欄也會被破壞。被破壞後,所有在調用await的線程就會退出,抛出BrokenBarrierException。
我們看一個簡單的例子,多個遊客線程分别在集合點A和B同步
CyclicBarrier應用示例
public class CyclicBarrierDemo {
static class Tourist extends Thread {
CyclicBarrier barrier;
public Tourist(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
try {
//模拟先各自獨立運作
Thread.sleep((int) (Math.random() * 1000));
//集合點A
barrier.await();
System.out.println(this.getName() + " arrived A "
+ System.currentTimeMillis());
//集合後模拟再各自獨立運作
Thread.sleep((int) (Math.random() * 1000));
//集合點B
barrier.await();
System.out.println(this.getName() + " arrived B "
+ System.currentTimeMillis());
} catch (InterruptedException e) {
} catch (BrokenBarrierException e) {
}
}
}
public static void main(String[] args) {
int num = 3;
Tourist[] threads = new Tourist[num];
CyclicBarrier barrier = new CyclicBarrier(num, new Runnable() {
@Override
System.out.println("all arrived " + System.currentTimeMillis()
+ " executed by " + Thread.currentThread().getName());
}
});
for(int i = 0; i < num; i++) {
threads[i] = new Tourist(barrier);
threads[i].start();
}
}
}
在筆者的計算機中的一次輸出為:
all arrived 1490053578552 executed by Thread-1
Thread-1 arrived A 1490053578555
Thread-2 arrived A 1490053578555
Thread-0 arrived A 1490053578555
all arrived 1490053578889 executed by Thread-0
Thread-0 arrived B 1490053578890
Thread-2 arrived B 1490053578890
Thread-1 arrived B 1490053578890
多個線程到達A和B的時間是一樣的,使用CyclicBarrier,達到了重複同步的目的。
CyclicBarrier與CountDownLatch可能容易混淆,我們強調下它們的差別。
1)CountDownLatch的參與線程是有不同角色的,有的負責倒計時,有的在等待倒計時變為0,負責倒計時和等待倒計時的線程都可以有多個,用于不同角色線程間的同步。
2)CyclicBarrier的參與線程角色是一樣的,用于同一角色線程間的協調一緻。
3)CountDownLatch是一次性的,而CyclicBarrier是可以重複利用的。
在這裡小編給大家分享一個Java入門的視訊教程,适合零基礎想要入門的小夥伴,有經驗的程式員也可以加以鞏固。
為初學者而著!
适合零基礎的小夥伴們學習Java
感興趣的小夥伴可以點視訊連結和小編一起學習,共同進步!
https://www.bilibili.com/video/BV1nm4y1F7ip/?spm_id_from=333.999.0.0&vd_source=a7816e3b2a3a67ac39dc87f6bf92421c
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiIUN40UP09zZuBnL0xWdhZWZk1ibvNWavw1cu92Yp9CXr5WaM5GZzN0LcNnbpdWdsB3LcJ3b0lGZlt2YvwFMuIjLyU2chVGblJ3LcxWb0h2Xy9GdpRWZfd2bsJ2LcV2chVGblJ3Lc52YucWbp5GZzN2Lc9CX6MHc0RHaiojIsJye.png)
https://www.bilibili.com/video/BV1nm4y1F7ip/?spm_id_from=333.999.0.0&vd_source=a7816e3b2a3a67ac39dc87f6bf92421c