CyclicBarrier源碼解讀

首先看他的兩個構造方法:

/** The number of parties */
private final int parties;
/* The command to run when tripped */
private final Runnable barrierCommand;
public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction;
}

public CyclicBarrier(int parties) {
    this(parties, null);
}

有兩個構造方法,parties就是線程數,兩個構造區別就是多了一個Runnable,他的作用就是:

當最後一個線程達到屏障點後,會執行runnable的run方法。

 

接下來分下核心方法awatit()->dowait(),在此之前先學習下該方法裏幾個成員變量的意思:

 

ReentrantLock lock = new ReentrantLock();

//條件隊列,當線程到達屏障處時候會阻塞放入到條件隊列裏

Condition trip = lock.newCondition();

//最後一個到達屏障的線程執行的操作

Runnable barrierCommand;

//代,所有線程到達屏障處就是一代,然後生成新一代

private static class Generation {

    boolean broken = false;

}

 

接下來,正式開始:

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

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
            //index=0表示最後一個線程到達了屏障處
            boolean ranAction = false;//這裏設置了一個布爾值ranAction,作用是來標識barrierCommand是否被正確執行完畢
            try {
                final Runnable command = barrierCommand;
                //如果構造方法有barrierCommand。則最後一個線程到屏障處要執行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)
                    //這裏就是如果到達屏障處,count-1後大於0,則放入到條件隊列
                    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;
            if (timed && nanos <= 0L) {
                breakBarrier();
                throw new TimeoutException();
            }
        }
    } finally {
        lock.unlock();
    }
}

private void breakBarrier() {
    generation.broken = true;
    count = parties;
    trip.signalAll();
}

private void nextGeneration() {
    // signal completion of last generation
    trip.signalAll();
    // set up next generation
    count = parties;
    generation = new Generation();
}

源碼看完,這裏終結下流程:

CyclicBarrier的原理就是通過ReentrantLock和Condition來實現的。

當線程執行到await()方法時候,會檢查是否是最後一個到達屏障處線程,如果是則執行構造方法裏的Runnable的run方法,並且生成新代,喚醒條件隊列裏的等待線程。

如果不是最後一個,則直接放入到條件隊列進行等待。

和CountDownLatch區別:

1.計數器是等待所有線程都執行完成,而柵欄是所有線程執行到一半的時候進行等待;

2.計數器的count是不能重置的,而柵欄到0的時候是可以進行重置的。

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