Java 併發程式設計(十四) -- CyclicBarrier原始碼分析

我很醜發表於2020-03-16

1. 類的定義

public class CyclicBarrier
複製程式碼

2. 欄位屬性

//獨佔鎖
private final ReentrantLock lock = new ReentrantLock();
//等待的條件
private final Condition trip = lock.newCondition();
//執行緒等待的數量,重置count
private final int parties;
//被喚醒時,優先執行的任務
private final Runnable barrierCommand;
//描述更新換代,重置?
//Generation中的broken表示這一次是否完成,預設false。count為0時設定為true
private Generation generation = new Generation();
//記錄當前需要等待到來的執行緒數,等於0表示到下一代,通過parties來重置
private int count;
複製程式碼

從欄位屬性可以看出

  • CyclicBarrier使用ReentrantLock來達到同步功能
  • 所有的執行緒等待Condition喚醒,即count為0的時候喚醒所有執行緒
  • CyclicBarrier的重置功能使用Generation和parties來完成
  • CyclicBarrier可以使用barrierCommand處理一部份邏輯

3. 構造方法

//傳入執行緒數量
public CyclicBarrier(int parties) {
    	//呼叫下面的構造方法
        this(parties, null);
    }

//傳入執行緒數量和要處理的業務
public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }
複製程式碼

從構造方法可以看出

  • count使用parties初始化
  • barrierCommand可以為null

4. 方法

nextGeneration 方法

//設定為新生代,喚醒執行緒並重置狀態
private void nextGeneration() {
        //喚醒所有等待condition的執行緒
        trip.signalAll();
        //重置count
        count = parties;
    	//重置generation,新生代
        generation = new Generation();
    }
複製程式碼

breakBarrier 方法

//設定當前代為完成狀態
private void breakBarrier() {
    	//設定當前代為完成狀態
        generation.broken = true;
    	//重置count
        count = parties;
    	//喚醒所有等待condition的執行緒
        trip.signalAll();
    }
複製程式碼

dowait 方法

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();
            }
            //count減1
            int index = --count;
            if (index == 0) {  // tripped
                //如果count為0,表示所有執行緒已經就緒
                boolean ranAction = false;
                try {
                    //先執行優先執行的任務
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    ranAction = true;
                    //設定為新生代,喚醒執行緒並重置狀態
                    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 {
                       //當前代已經改變,中斷當前執行緒
                        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();
        }
    }
複製程式碼

getParties 方法

//獲取設定等待的執行緒數
public int getParties() {
        return parties;
    }
複製程式碼

await 方法

//進入條件等待
public int await() throws InterruptedException, BrokenBarrierException {
        try {
            //呼叫dowait方法
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }
//進入有超時時間的條件等待
public int await(long timeout, TimeUnit unit)
        throws InterruptedException,
               BrokenBarrierException,
               TimeoutException {
                   //呼叫dowait方法
        return dowait(true, unit.toNanos(timeout));
    }
複製程式碼

isBroken 方法

//獲取當前代狀態
public boolean isBroken() {
    	//上鎖
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //返回當前代狀態
            return generation.broken;
        } finally {
            //釋放鎖資源
            lock.unlock();
        }
    }
複製程式碼

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();
        }
    }
複製程式碼

getNumberWaiting 方法

//獲取等待中的執行緒數
public int getNumberWaiting() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //parties 需要的執行緒總數
            //count 還需要等待到來的執行緒數
            return parties - count;
        } finally {
            lock.unlock();
        }
    }
複製程式碼

相關文章