原始碼分析:Phaser 之更靈活的同步屏障

Admol發表於2021-02-22

簡介

Phaser 是 JDK 1.7 開始提供的一個可重複使用的同步屏障,功能類似於CyclicBarrierCountDownLatch,但使用更靈活,支援對任務的動態調整,並支援分層結構來達到更高的吞吐量。

Registration(註冊)

與其他屏障的情況不同,在 Phaser 上註冊同步的參與方的數量可能隨時間而變化。任務可以在任何時候註冊(使用方法registerbulkRegister或建立初始參與方數量的建構函式),可以在任何到達時取消註冊(使用arriveAndDeregister),註冊和登出隻影響內部計數,任務無法查詢它們是否已註冊。

Synchronization(同步)

CyclicBarrierPhaser也可以重複await。方法arriveAndAwaitAdvance()有效果類似於CyclicBarrier.await 。phaser的每一代都有一個相關的phase number,初始值為0,當所有註冊的任務都到達phaser時phase+1,到達最大值(Integer.MAX_VALUE)之後清零。使用phase number可以獨立控制到達phaser 和 等待其他執行緒 的動作,通過下面兩種型別的方法:

  • Arrival(到達機制)
    arrivearriveAndDeregister方法記錄到達狀態。
    這些方法不會阻塞,但是會返回一個相關的arrival phase number;也就是說,phase number用來確定到達狀態。當所有任務都到達給定phase時,可以執行一個可選的函式,這個函式通過重寫onAdvance方法實現,通常可以用來控制終止狀態。
    重寫此方法類似於為CyclicBarrier提供一個barrierAction(執行的命令執行緒),但比它更靈活。
  • Waiting(等待機制)
    awaitAdvance方法需要一個表示 arrival phase number 的引數,並且在phaser前進到與給定phase不同的phase時返回。和CyclicBarrier不同,即使等待執行緒已經被中斷,awaitAdvance方法也會一直等待。中斷狀態和超時時間同樣可用,但是當任務等待中斷或超時後未改變phaser的狀態時會遭遇異常。如果有必要,在方法forceTermination之後可以執行這些異常的相關的handler進行恢復操作,Phaser也可能被ForkJoinPool中的任務使用,這樣在其他任務阻塞等待一個phase時可以保證足夠的並行度來執行任務。

Termination(終止機制)

可以用isTerminated方法檢查phaser的終止狀態。

在終止時,所有同步方法立刻返回一個負值。

在終止時嘗試註冊也沒有效果。當呼叫onAdvance返回true時Termination被觸發。當deregistration操作使已註冊的parties變為0時,onAdvance的預設實現就會返回true。也可以重寫onAdvance方法來定義終止動作。forceTermination方法也可以釋放等待執行緒並且允許它們終止。

Tiering(分層結構)

Phaser支援分層結構(樹狀構造)來減少競爭。

註冊了大量parties的Phaser可能會因為同步競爭消耗很高的成本, 因此可以設定一些子Phaser來共享一個通用的parent。這樣的話即使每個操作消耗了更多的開銷,但是會提高整體吞吐量。
在一個分層結構的phaser裡,子節點phaser的註冊和取消註冊都通過父節點管理。

子節點phaser通過構造或方法registerbulkRegister進行首次註冊時,在其父節點上註冊。子節點phaser通過呼叫arriveAndDeregister進行最後一次取消註冊時,也在其父節點上取消註冊。

Monitoring(狀態監控)

由於同步方法可能只被已註冊的parties呼叫,所以phaser的當前狀態也可能被任何呼叫者監控。在任何時候,可以通過getRegisteredParties獲取parties數,其中getArrivedParties方法返回已經到達當前phase的parties數。當剩餘的parties(通過方法getUnarrivedParties獲取)到達時,phase進入下一代。這些方法返回的值可能只表示短暫的狀態,所以一般來說在同步結構裡並沒有啥卵用。

分層執行示意圖

使用示例

void runTasks(List<Runnable> tasks) throws InterruptedException{
        // "1" to register self
        final Phaser phaser = new Phaser(1);
        // create and start threads
        for (final Runnable task : tasks) {
            phaser.register();
            new Thread() {
                @Override
                public void run() {
                    // await all creation
                    // 類似 CountDownLatch.await() 和  CyclicBarrier.await()
                    System.out.println("等待所有的任務+1");
                    phaser.arriveAndAwaitAdvance();
                    task.run();
                }
            }.start();
        }

        // allow threads to start and deregister self
         TimeUnit.SECONDS.sleep(1);
        System.out.println("jinglingwang.cn 放行。。。。。。");
        // 類似 CountDownLatch.countDown() 減到了0 和 CyclicBarrier 中的最後一個執行緒呼叫了await()
        phaser.arriveAndDeregister();
    }

多階段執行示例

這裡的階段有點類似多次使用CyclicBarrier,並不是Phaser的分層

void runTasks2() {
     // 定義階段數
     int phases = 3;
     // 進入下一個階段需要的參與數(執行緒數)
     int parties = 5;
     // 自定義onAdvance  https://jinglingwang.cn
     Phaser phaser = new Phaser(parties){
         @Override
         protected boolean onAdvance(int phase,int registeredParties){
             System.out.println("階段phase: "+(phase +1) +" 執行完畢");
             return phase > phases || registeredParties == 0;
         }
     };
    for(int i = 1; i <= parties; i++){
        new Thread(()->{
            for(int j = 1; j <= phases; j++){
                System.out.println(Thread.currentThread().getName() + " doing 階段:"+ j);
                phaser.arriveAndAwaitAdvance();
            }
        },"Thread-"+i).start();
    }
}

執行結果:

Thread-1 doing 階段:1
Thread-4 doing 階段:1
Thread-3 doing 階段:1
Thread-2 doing 階段:1
Thread-5 doing 階段:1
階段phase: 1 執行完畢
Thread-5 doing 階段:2
Thread-3 doing 階段:2
Thread-4 doing 階段:2
Thread-1 doing 階段:2
Thread-2 doing 階段:2
階段phase: 2 執行完畢
Thread-2 doing 階段:3
Thread-3 doing 階段:3
Thread-1 doing 階段:3
Thread-4 doing 階段:3
Thread-5 doing 階段:3
階段phase: 3 執行完畢

原始碼分析

內部類QNode

內部等待佇列,用於在阻塞時記錄等待執行緒及相關資訊

static final class QNode implements ForkJoinPool.ManagedBlocker {
    final Phaser phaser;
    final int phase;
    final boolean interruptible;
    final boolean timed;
    boolean wasInterrupted;
    long nanos;
    final long deadline;
    volatile Thread thread; // nulled to cancel wait
    QNode next;  // 由此看出是一個單向列表

    QNode(Phaser phaser, int phase, boolean interruptible,
          boolean timed, long nanos) {
        this.phaser = phaser;
        this.phase = phase;
        this.interruptible = interruptible;
        this.nanos = nanos;
        this.timed = timed;
        this.deadline = timed ? System.nanoTime() + nanos : 0L;
        thread = Thread.currentThread();
    }
  ...  部分程式碼省略 ...
}

主要的屬性

// 狀態變數,用於儲存當前階段phase、參與者數parties、未完成的參與者數unarrived_count
// 低0-15位表示未到達parties數,中16-31位表示等待的parties數,中32-62位表示當前階段phase
private volatile long state;
// 最多可以有多少個參與者,即每個階段最多有多少個任務,十進位制表示為65535
private static final int  MAX_PARTIES     = 0xffff;
// 最多可以有多少階段,2的31次方-1,十進位制:2147483647
private static final int  MAX_PHASE       = Integer.MAX_VALUE;
// 參與者數量的偏移量
private static final int  PARTIES_SHIFT   = 16;
// 階段的偏移量
private static final int  PHASE_SHIFT     = 32;
// 未完成的參與者數的掩碼,低16位,二進位制:1111 1111 1111 1111
private static final int  UNARRIVED_MASK  = 0xffff;      // to mask ints
// 參與者數,中間16位,二進位制:1111 1111 1111 1111 0000 0000 0000 0000
private static final long PARTIES_MASK    = 0xffff0000L; // to mask longs
// counts的掩碼,counts等於參與者數和未完成的參與者數的'|'操作
// 二進位制:1111 1111 1111 1111 1111 1111 1111 1111
private static final long COUNTS_MASK     = 0xffffffffL;
// 二進位制位第64位為1,終止位
private static final long TERMINATION_BIT = 1L << 63;

// 一些特殊的值
// 一次一個參與者完成
private static final int  ONE_ARRIVAL     = 1;
// 增加減少參與者時使用,1左移16位,二進位制:0001 0000 0000 0000 0000
private static final int  ONE_PARTY       = 1 << PARTIES_SHIFT;
// 減少參與者時使用,二進位制:0001 0000 0000 0000 0001
private static final int  ONE_DEREGISTER  = ONE_ARRIVAL|ONE_PARTY;
// 沒有參與者時使用
private static final int  EMPTY           = 1;

// 當前Phaser的父級;如果沒有,則為null
private final Phaser parent;

/** phaser的根。如果不在樹中則等於phaser */
private final Phaser root;

/** 兩個佇列連結串列,在偶數和奇數階段交替使用 */
private final AtomicReference<QNode> evenQ; // 偶數
private final AtomicReference<QNode> oddQ;  // 奇數

構造方法

public Phaser() {
    this(null, 0);
}

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

public Phaser(Phaser parent) {
    this(parent, 0);
}

public Phaser(Phaser parent, int parties) {
    if (parties >>> PARTIES_SHIFT != 0)
        throw new IllegalArgumentException("Illegal number of parties");
    int phase = 0;
    this.parent = parent;
    if (parent != null) { // 有設定parent
        final Phaser root = parent.root;
        this.root = root;
        this.evenQ = root.evenQ;
        this.oddQ = root.oddQ;
        if (parties != 0)
            phase = parent.doRegister(1);
    }
    else {
        this.root = this; // root是當前phaser
        // 初始化兩個佇列
        this.evenQ = new AtomicReference<QNode>(); 
        this.oddQ = new AtomicReference<QNode>();
    }
    // 確定state,先是一個三目運算
    // parties 為 0 時,state為 1
    // 
    this.state = (parties == 0) ? (long)EMPTY :
        ((long)phase << PHASE_SHIFT) |       // 當前階段左移32位
        ((long)parties << PARTIES_SHIFT) |   // 等待的parties數,左移16位
        ((long)parties);                     // 未到達parties數,就存低16位
}

整個構造方法最重要的就是最後state值的確認,也可以看出低0-15位表示未到達parties數,中16-31位表示等待的parties數,中32-62位表示當前階段phase。

比如入參為5的話,初始化的state值的二進位制表示為:0101 0000 0000 0000 0101

register()方法

方法說明:向當前phaser新增一個新的unarrived(未到達)的party,如果onAdvance正在執行,那麼這個方法會等待它執行結束再返回結果。如果當前phaser有父節點,並且當前phaser上沒有已註冊的party,那麼就會交給父節點註冊。

程式碼分析:

public int register() {
    return doRegister(1);
}

private int doRegister(int registrations) {
    // 調整的狀態,等待的parties數和unarrived(未到達)parties數同時增加
    long adjust = ((long)registrations << PARTIES_SHIFT) | registrations;
    final Phaser parent = this.parent;
    int phase;
    for (;;) { //自旋
        long s = (parent == null) ? state : reconcileState(); // 取state值
        // 轉換成int,state的低32位,也就是parties和unarrived的值
        int counts = (int)s;
        // 取等待的parties數
        int parties = counts >>> PARTIES_SHIFT;
        // UNARRIVED_MASK,低16位,二進位制:1111 1111 1111 1111
        // 也就是取低16中存的未到達數parties數
        int unarrived = counts & UNARRIVED_MASK;
        // 1 > 65535 - parties 
        if (registrations > MAX_PARTIES - parties) // 檢查容量
            throw new IllegalStateException(badRegister(s));
        phase = (int)(s >>> PHASE_SHIFT); // 無符號右移32位,取出當前的階段phase
        if (phase < 0)
            break; // 退出自旋,返回phase ,也就是負數
        // 不是第一個參與者
        if (counts != EMPTY) {                  // not 1st registration
            if (parent == null || reconcileState() == s) {
                if (unarrived == 0)// unarrived等於0說明當前階段正在執行onAdvance()方法,等待advance方法退出
                    root.internalAwaitAdvance(phase, null); // 阻塞並等待階段前進
                else if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s + adjust))
                    // 使用CAS的方式修改state值,增加adjust,成功的話退出自旋,返回phase 
                    break;
            }
        } else if (parent == null) {// 沒有設定父節點
            // 計算state的值
            long next = ((long)phase << PHASE_SHIFT) | adjust;
            if (UNSAFE.compareAndSwapLong(this, stateOffset, s, next))
                // CAS 修改成功則退出自旋
                break;
        }  else { //以上兩種情況都不是,有多層級的時候
            synchronized (this) {               // 1st sub registration
                if (state == s) {               // recheck under lock
                    phase = parent.doRegister(1); // 交給父節點完成註冊
                    if (phase < 0) 
                        break; //退出自旋,返回phase ,也就是負數
                    // 走到這兒,說明父節點註冊成功了(phase大於0),while自旋,直到CAS修改成功
                    while (!UNSAFE.compareAndSwapLong(this, stateOffset, s,((long)phase << PHASE_SHIFT) | adjust)) {
                        s = state;
                        phase = (int)(root.state >>> PHASE_SHIFT);
                        // assert (int)s == EMPTY;
                    }
                    break;
                }
            }
        }
    }
    return phase;
}

reconcileState()方法

子Phaser的phase在沒有被真正使用之前,允許滯後於它的root節點。非首次註冊時,如果Phaser有父節點,則呼叫reconcileState()方法解決root節點的phase延遲傳遞問題.

當root節點的phase已經advance到下一代,但是子節點phaser還沒有,這種情況下它們必須通過更新未到達parties數 完成它們自己的advance操作(如果parties為0,重置為EMPTY狀態)。

private long reconcileState() {
    final Phaser root = this.root;
    long s = state;
    if (root != this) {
        int phase, p;
        // CAS to root phase with current parties, tripping unarrived
        while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
               (int)(s >>> PHASE_SHIFT) &&
               !UNSAFE.compareAndSwapLong(this, stateOffset, s,
               s = (((long)phase << PHASE_SHIFT) |
                     ((phase < 0) ? (s & COUNTS_MASK) :
                      (((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
                       ((s & PARTIES_MASK) | p))))))
            s = state;
    }
    return s;
}

internalAwaitAdvance()方法:

除非終止,否則可能會阻塞或等待phase前進到下一代

private int internalAwaitAdvance(int phase, QNode node) {
    // assert root == this;
    // 確保舊佇列是乾淨的 
    releaseWaiters(phase-1);          // ensure old queue clean
    // 入隊成功變為true
    boolean queued = false;           // true when node is enqueued
    int lastUnarrived = 0;            // to increase spins upon change
    int spins = SPINS_PER_ARRIVAL; //自旋的次數,(NCPU < 2) ? 1 : 1 << 8;1或者256次
    long s;
    int p;
    while ((p = (int)((s = state) >>> PHASE_SHIFT)) == phase) { // 無符號右移32位,得到當前階段,檢查是否有變化
        if (node == null) {           // spinning in noninterruptible mode
            int unarrived = (int)s & UNARRIVED_MASK; // 與掩碼計算,得到低16位代表的未到達數
            // 未到達數有變化且小於CPU核數
            if (unarrived != lastUnarrived && (lastUnarrived = unarrived) < NCPU)
                spins += SPINS_PER_ARRIVAL; // 增加自旋次數
            boolean interrupted = Thread.interrupted(); // 執行緒中斷
            if (interrupted || --spins < 0) { // need node to record intr
                // 執行緒被中斷了或者自旋次數小於0,需要節點記錄索引
                node = new QNode(this, phase, false, false, 0L);
                node.wasInterrupted = interrupted;
            }
        }else if (node.isReleasable()) // done or aborted
            break; // 完成或者終止,退出自旋
        else if (!queued) {           // 推入佇列
            // (phase & 1 == 0 )通過位運算快速判斷是奇偶數
            AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
            QNode q = node.next = head.get();
            // 再次判斷
            if ((q == null || q.phase == phase) &&  (int)(state >>> PHASE_SHIFT) == phase) // avoid stale enq
                queued = head.compareAndSet(q, node); //  CAS修改入隊
        } else {
            try {
                ForkJoinPool.managedBlock(node); // 阻塞node,等待被喚醒
            } catch (InterruptedException ie) {
                node.wasInterrupted = true;
            }
        }
    }
    // 執行緒已經被喚醒,並且phase已經有變化了才會退出上面的自旋,或者完成終止,退出自旋
    if (node != null) {
        if (node.thread != null)
            node.thread = null;       // 避免 unpark()
        if (node.wasInterrupted && !node.interruptible)
            Thread.currentThread().interrupt();
        if (p == phase && (p = (int)(state >>> PHASE_SHIFT)) == phase)
            return abortWait(phase); // possibly clean up on abort
    }
    // 喚醒當前phaser階段的執行緒
    releaseWaiters(phase);
    return p;
}

/** 從佇列中刪除執行緒,喚醒當前phaser階段的執行緒 */
private void releaseWaiters(int phase) {
    QNode q;   // 佇列的第一個元素
    Thread t;  // its thread
    // 再次根據當前phaser選擇對應的佇列
    AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
    while ((q = head.get()) != null && q.phase != (int)(root.state >>> PHASE_SHIFT)) {
        if (head.compareAndSet(q, q.next) && (t = q.thread) != null) {
            // 刪掉q節點,喚醒q節點中的執行緒
            q.thread = null;
            LockSupport.unpark(t); // 喚醒執行緒
        }
    }
}

register()方法總結:

  1. register方法為phaser新增一個新的party,如果onAdvance正在執行,那麼這個方法會等待它執行結束再返回結果。
  2. register和bulkRegister都由doRegister實現,bulkRegister是批量註冊新增
  3. 使用了自旋 + CAS 技術來保證更新成功
  4. 如果前階段正在執行onAdvance()方法,則需要阻塞等待(根據phase入相應佇列)其執行完後再進行註冊
  5. 當前phaser如果有父節點,需要交由父節點來完成註冊

arrive()方法

使當前執行緒到達phaser,不等待其他任務到達。返回arrival phase number。

public int arrive() {
    // 一次一個參與者完成
    return doArrive(ONE_ARRIVAL); // 特殊的屬性值 ONE_ARRIVAL: 1
}

private int doArrive(int adjust) {
    final Phaser root = this.root;
    for (;;) { // 自旋
        long s = (root == this) ? state : reconcileState(); // 確定state值
        int phase = (int)(s >>> PHASE_SHIFT);  //位運算,得到當前階段phaser
        if (phase < 0)
            return phase;
        int counts = (int)s; // 表示parties和unarrived的值
        int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK); // 計算未到達數
        if (unarrived <= 0)
            throw new IllegalStateException(badArrive(s)); // 到達時邊界異常
        if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s-=adjust)) { // CAS直接修改state
            if (unarrived == 1) { // == 1 表示當前為最後一個未到達的任務
                long n = s & PARTIES_MASK;  // 掩碼計算當前parties, 保留了16-32位的部分
                int nextUnarrived = (int)n >>> PARTIES_SHIFT;
                if (root == this) {
                    if (onAdvance(phase, nextUnarrived))// 判斷 registeredParties == 0,返回true,需要終止phaser
                        n |= TERMINATION_BIT; // 標識終止位
                    else if (nextUnarrived == 0)
                        n |= EMPTY;
                    else
                        n |= nextUnarrived;
                    int nextPhase = (phase + 1) & MAX_PHASE; // 下一個階段phaser
                    n |= (long)nextPhase << PHASE_SHIFT;     // 下一個階段phaser左移32位再加上當前的phaser就是最新的phaser
                    UNSAFE.compareAndSwapLong(this, stateOffset, s, n);  //CAS 修改
                    releaseWaiters(phase);  // 釋放等待phase的執行緒
                } else if (nextUnarrived == 0) { // propagate deregistration
                    phase = parent.doArrive(ONE_DEREGISTER); // 使用父節點管理
                    UNSAFE.compareAndSwapLong(this, stateOffset, s, s | EMPTY);
                } else
                    phase = parent.doArrive(ONE_ARRIVAL);    // 使用父節點管理
            }
            // 不是最後一個到達,直接返回phaser
            return phase;
        }
    }
}

arrive()方法總結:

  1. 通過位運算計算當前state、phaser等值
  2. 然後直接使用自旋+CAS更新state值(state-=adjust
  3. 如果當前不是最後一個未到達的任務,直接返回當前phaser值
  4. 如果當前是最後一個未到達的任務
    1. 如果當前是root節點,判斷是否需要終止phase(nextUnarrived == 0)r,然後CAS更新state,最後釋放等待phase的執行緒
    2. 如果是分層結構,並且已經沒有下一代未到達的parties,則交由父節點處理doArrive邏輯,然後更新state為EMPTY

arriveAndDeregister()方法

使當前執行緒到達phaser並撤銷註冊,返回arrival phase number。

arriveAndDeregister()方法和arrive()方法非常類似,都是呼叫的doArrive()方法,只是入參有些區別,arriveAndDeregister()方法傳入的入參是ONE_DEREGISTER,同時減參與者和未到達者。

arriveAndAwaitAdvance()方法

到達並等待其他人到達

public int arriveAndAwaitAdvance() {
    // Specialization of doArrive+awaitAdvance eliminating some reads/paths
    final Phaser root = this.root;
    for (;;) { // 自旋
        // 當前state值
        long s = (root == this) ? state : reconcileState();
        int phase = (int)(s >>> PHASE_SHIFT); // 位運算-->當前階段
        if (phase < 0)  // onAdvance()方法返回true後,中斷位標識後phase就會小於0
            return phase;
        int counts = (int)s; // =>int
        // 未到達數
        int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
        if (unarrived <= 0)
            throw new IllegalStateException(badArrive(s)); // 到達時邊界異常
        // CAS 修改state值  s-=1
        if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s -= ONE_ARRIVAL)) { 
            if (unarrived > 1) // 還是超過1個未到達,加入佇列阻塞等待
                return root.internalAwaitAdvance(phase, null);
            // 到下面這裡,說明是最後一個到達
            if (root != this) // root 不是當前自己,交由父節點阻塞等待
                return parent.arriveAndAwaitAdvance();
            // 位運算,得到parties,s是CAS計算過後的值,
            long n = s & PARTIES_MASK;  // base of next state
            // 即下一次需要到達的參與者數量
            int nextUnarrived = (int)n >>> PARTIES_SHIFT;
            if (onAdvance(phase, nextUnarrived)) // 判斷是否要終止,nextUnarrived == 0
                n |= TERMINATION_BIT;            // 標識終止位
            else if (nextUnarrived == 0)
                n |= EMPTY;
            else
                n |= nextUnarrived; // n 加上unarrived的值,下個階段
            int nextPhase = (phase + 1) & MAX_PHASE; // +1,進入下一個階段
            n |= (long)nextPhase << PHASE_SHIFT;     // 標識到具體的位
            if (!UNSAFE.compareAndSwapLong(this, stateOffset, s, n))  // CAS 修改
                return (int)(state >>> PHASE_SHIFT); // terminated
            releaseWaiters(phase); // 喚醒當前階段的執行緒,可以進行下一段了
            return nextPhase;  //返回下一階段
        }
    }
}

arriveAndAwaitAdvance()方法總結:

  1. 主要邏輯就是自旋+CAS 修改state中低16的unarrived的值-1,知道自旋修改成功
  2. 如果呼叫當前的執行緒不是最後一個到達,需要入隊阻塞等待
  3. 如果是最後一個到達的執行緒,則呼叫onAdvance()方法,返回true表示需要被中斷,之後的phase就會小於0,再次呼叫arriveAndAwaitAdvance()方法也就麼有阻塞等待效果了
  4. onAdvance()方法支援重寫,我們可以自定義判斷規則

awaitAdvance()方法

等待指定phase數,返回下一個 arrival phase number。

public int awaitAdvance(int phase) {
    final Phaser root = this.root;
    long s = (root == this) ? state : reconcileState();
    int p = (int)(s >>> PHASE_SHIFT); // 當前階段
    if (phase < 0)
        return phase;
    if (p == phase)
        // 阻塞或等待phase前進到下一代,internalAwaitAdvance見上面程式碼分析
        return root.internalAwaitAdvance(phase, null);
    return p;
}

Phaser 總結

  1. Phaser 使用了state變數來維護各個邏輯狀態的計數
  2. state的低0-15位表示未到達parties數,中16-31位表示等待的parties數,中32-62位表示當前階段phase,第64位為終止位
  3. 維護的QNode佇列根據當前階段的奇偶性來選擇,判斷奇偶性可以使用(phase & 1) == 0來快速判斷
  4. 每個階段最後一個參與者到達時,會喚醒佇列中的執行緒進入到下一階段,不是最後一個參與者到達會阻塞等待
  5. 重寫onAdvance方法可以達到CyclicBarrier的barrierAction類似效果,即在階段完成執行指定的命令

於CyclicBarrier和CountDownLatch比較靈活在那裡?

  1. Phaser 支援分層,支援多個階段,功能更加豐富與靈活
  2. 可以使用register方法追加參與者;By: https://jinglingwang.cn
  3. 也可以使用arriveAndDeregister方法到達但是不用等待
  4. CountDownLatch 不支援迴圈使用,只能控制一個或一組執行緒
  5. CyclicBarrier 支援迴圈使用,但不支援分層,不支援修改任務數

相關文章