jdk源碼解析四之CyclicBarrier

CyclicBarrier

阻塞一組線程直到某件事發生,可重複使用,另一種柵欄式。5個人約好集合後去其他地方。

    public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        //屏障攔截的線程數量
        this.parties = parties;
        //線程數量
        this.count = parties;
        //指定個數線程被wait後,執行的後續方法
        this.barrierCommand = barrierAction;
    }

await

    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }

```java
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();

            //線程中斷處理
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }

            //獲取下標
            int index = --count;
            //說明最後一個調用了
            if (index == 0) {  // tripped
                boolean ranAction = false;
                try {
                    //獲取柵欄任務
                    final Runnable command = barrierCommand;
                    if (command != null)
                        //執行
                        command.run();
                    ranAction = true;
                    //重新構造可wait線程數
                    //以及換代
                    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 {
                     //說明這個線程不是當代的,就不會影響當代執行,則中斷線程
                        //如果在等待過程中,線程被中斷了,就拋出異常。但如果中斷的線程所對應的CyclicBarrier不是這代的,
                        // 比如,在最後一次線程執行signalAll後,並且更新了這個“代”對象。在這個區間,
                        // 這個線程被中斷了,那麼,JDK認爲任務已經完成了,就不必在乎中斷了,只需要打個標記。
                        // 該部分源碼已在dowait(boolean, long)方法中進行了註釋
                        Thread.currentThread().interrupt();
                    }
                }

                if (g.broken)
                    throw new BrokenBarrierException();

                //表示正常換代了,返回當前線程所在下標,便於下次做選舉等操作
                //仔細發現,柵欄不是一次性的,可以重複使用多次,但是鎖是同一個,所以需要用generation進行區分,是否是同一個柵欄
                if (g != generation)
                    return index;

                //超時,標記柵欄損壞,且拋出異常
                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            //釋放鎖
            lock.unlock();
        }
    }

  private void nextGeneration() {
        // signal completion of last generation
        //喚醒所有線程
        trip.signalAll();
        // set up next generation
        //count恢復parties個數
        count = parties;
        //換代
        generation = new Generation();
    }

    private void breakBarrier() {
        //標記柵欄損壞
        generation.broken = true;
        //count恢復parties個數
        count = parties;
        //喚醒所有線程
        trip.signalAll();
    }

reset

    public void reset() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            breakBarrier();   // break the current generation
            nextGeneration(); // start a new generation
        } finally {
            lock.unlock();
        }
    }

總結:可重複使用多次,底層採用顯示鎖進行加鎖,
索引按照初始count遞減,當索引爲0時,執行柵欄任務
當執行成功,通知當代所有線程,接着換代,如果當代有線程中斷了,且已經執行了換代任務了,這個時候會將中斷線程標記中斷

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章