天天看點

Java基礎—循環栅欄CyclicBarrier

循環栅欄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

Java基礎—循環栅欄CyclicBarrier

https://www.bilibili.com/video/BV1nm4y1F7ip/?spm_id_from=333.999.0.0&vd_source=a7816e3b2a3a67ac39dc87f6bf92421c