首頁 > Java > java教程 > Java中的CyclicBarrier源碼分析

Java中的CyclicBarrier源碼分析

WBOY
發布: 2023-04-30 20:55:13
轉載
1397 人瀏覽過

    CyclicBarrier簡介

    對於CountDownLatch,其他執行緒為遊戲玩家,例如英雄聯盟,主執行緒為控制遊戲開始的線程。在所有的玩家都準備好之前,主執行緒是處於等待狀態的,也就是遊戲不能開始。當所有的玩家準備好之後,下一步的動作實施者為主線程,即開始遊戲。

    對於CyclicBarrier,假設有一家公司要全體員工進行團建活動,活動內容為翻越三個障礙物,每一個人翻越障礙物所花的時間是不一樣的。但公司要求所有人在翻越當前障礙物之後再開始翻越下一個障礙物,也就是所有人翻越第一個障礙物之後,才開始翻越第二個,以此類推。類比地,每一個員工都是一個「其他線程」。當所有人都翻越的所有的障礙物之後,程序才結束。而主線可能早就結束了,這裡我們不用管主線。

    CyclicBarrier原始碼分析

    類別的繼承關係

    CyclicBarrier沒有顯示繼承哪個父類別或實作哪個父介面, 所有AQS和重入鎖定不是透過繼承實現的,而是透過組合實現的。

    public class CyclicBarrier {}
    ```  
    
    ### 类的内部类
    
    CyclicBarrier类存在一个内部类Generation,每一次使用的CycBarrier可以当成Generation的实例,其源代码如下
    
    ```java
    private static class Generation {
    boolean broken = false;
    }
    登入後複製

    說明: Generation類別有一個屬性broken,用來表示目前屏障是否被損壞。

    類別的屬性

    public class CyclicBarrier {
    
    /** The lock for guarding barrier entry */
    // 可重入锁
    private final ReentrantLock lock = new ReentrantLock();
    /** Condition to wait on until tripped */
    // 条件队列
    private final Condition trip = lock.newCondition();
    /** The number of parties */
    // 参与的线程数量
    private final int parties;
    /* The command to run when tripped */
    // 由最后一个进入 barrier 的线程执行的操作
    private final Runnable barrierCommand;
    /** The current generation */
    // 当前代
    private Generation generation = new Generation();
    // 正在等待进入屏障的线程数量
    private int count;
    }
    登入後複製

    說明: 該屬性有一個為ReentrantLock對象,有一個為Condition對象,而Condition對象又是基於AQS的,所以,歸根到底,底層還是由AQS提供支援。

    類別的建構子

    CyclicBarrier(int, Runnable)型別建構子

    public CyclicBarrier(int parties, Runnable barrierAction) {
    // 参与的线程数量小于等于0,抛出异常
    if (parties <= 0) throw new IllegalArgumentException();
    // 设置parties
    this.parties = parties;
    // 设置count
    this.count = parties;
    // 设置barrierCommand
    this.barrierCommand = barrierAction;
    }
    登入後複製

    說明: 此建構函式可以指定關聯該CyclicBarrier的執行緒數量,並且可以指定在所有執行緒都進入屏障後的執行動作,該執行動作由最後一個進行屏障的執行緒執行。

    CyclicBarrier(int)型建構子

    public CyclicBarrier(int parties) {
    // 调用含有两个参数的构造函数
    this(parties, null);
    }
    登入後複製

    說明: 此建構子僅僅執行了關聯該CyclicBarrier的線程數量,沒有設定執行動作。

    核心函數- dowait函數

    此函數為CyclicBarrier類別的核心函數,CyclicBarrier類別對外提供的await函數在底層都是呼叫該了doawait函數,

    其原始程式碼如下:

    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) { // 正在等待进入屏障的线程数量为0,所有线程都已经进入
    // 运行的动作标识
    boolean ranAction = false;
    try {
    // 保存运行动作
    final Runnable command = barrierCommand;
    if (command != null) // 动作不为空
    // 运行
    command.run();
    // 设置ranAction状态
    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) // 设置了等待时间,并且等待时间大于0
    // 等待指定时长
    nanos = trip.awaitNanos(nanos);
    } catch (InterruptedException ie) {
    if (g == generation && ! g.broken) { // 等于当前代并且屏障没有被损坏
    // 损坏当前屏障
    breakBarrier();
    // 抛出异常
    throw ie;
    } else { // 不等于当前带后者是屏障被损坏
    // We&#39;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) { // 设置了等待时间,并且等待时间小于0
    // 损坏屏障
    breakBarrier();
    // 抛出异常
    throw new TimeoutException();
    }
    }
    } finally {
    // 释放锁
    lock.unlock();
    }
    }
    登入後複製

    核心函數- nextGeneration函數

    此函數在所有執行緒進入屏障後會被調用,即產生下一個版本,所有執行緒又可以重新進入到屏障中,

    其原始程式碼如下:

    private void nextGeneration() {
    // signal completion of last generation
    // 唤醒所有线程
    trip.signalAll();
    // set up next generation
    // 恢复正在等待进入屏障的线程数量
    count = parties;
    // 新生一代
    generation = new Generation();
    }
    登入後複製

    在此函數中會呼叫AQS的signalAll方法,也就是喚醒所有等待執行緒。如果所有的執行緒都在等待此條件,則喚醒所有執行緒。

    其原始碼如:

    public final void signalAll() {
    if (!isHeldExclusively()) // 不被当前线程独占,抛出异常
    throw new IllegalMonitorStateException();
    // 保存condition队列头节点
    Node first = firstWaiter;
    if (first != null) // 头节点不为空
    // 唤醒所有等待线程
    doSignalAll(first);
    }
    登入後複製

    以上是Java中的CyclicBarrier源碼分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    相關標籤:
    來源:yisu.com
    本網站聲明
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
    熱門教學
    更多>
    最新下載
    更多>
    網站特效
    網站源碼
    網站素材
    前端模板