概述
Phaser 是一个同步辅助类,与CyclicBarrier和CountDownLatch功能相似,用于栅栏条件的相互等待,支持更丰富的用法, 可以将一个的程序的等待分为多个阶段。
主状态分为 4部分,1~16位 未到达者数,17~32位参与数 parties,33~62 阶段值 phase, 63位 结束标识, 64位正负标识
private volatile long state;
//evenQ,oddQ都是里面放Node节点的CAS工具类,方便执行CAS 替换Node节点
//evenQ,oddQ中放的都是头结点,节点构成一个单项列表, 在头部插入节点。
private final AtomicReference<QNode> evenQ;
private final AtomicReference<QNode> oddQ;
源码分析
Phaser构造方法
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) {//如果父节点不为空
final Phaser root = parent.root;
this.root = root;//父节点的root就是当前的root
this.evenQ = root.evenQ;//使用父节点的队列容器
this.oddQ = root.oddQ;//同上
if (parties != 0)//如果参与者数不为0
phase = parent.doRegister(1);//父类注册一个参与者。
}
else {//没有父节点 初始化 root, evenQ,oddQ
this.root = this;
this.evenQ = new AtomicReference<QNode>();
this.oddQ = new AtomicReference<QNode>();
}//获取主状态值
this.state = (parties == 0) ? (long)EMPTY :
((long)phase << PHASE_SHIFT) |
((long)parties << PARTIES_SHIFT) |
((long)parties);
}
如果没有父节点 root==this,evenQ,oddQ都是新创建的。
分析一下Node
构造方法
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.lastTime = timed ? System.nanoTime() : 0L;
thread = Thread.currentThread();
}
存放了phaser,阶段值phase,是否可打断, 超时时间,创建线程。
public boolean isReleasable() {
if (thread == null)
return true;
if (phaser.getPhase() != phase) {
thread = null;
return true;
}
if (Thread.interrupted())
wasInterrupted = true;
if (wasInterrupted && interruptible) {
thread = null;
return true;
}
if (timed) {
if (nanos > 0L) {
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
}
if (nanos <= 0L) {
thread = null;
return true;
}
}
return false;
}
在thread为空,phaser的阶段值与当前阶段值phase不同,被打断,超时返回ture,否则返回false
public boolean block() {
if (isReleasable())
return true;
else if (!timed)
LockSupport.park(this);
else if (nanos > 0)
LockSupport.parkNanos(this, nanos);
return isReleasable();
}
block是阻塞方法。
register分析
一个线程加入Phaser活动,要先执行register。
public int register() {
return doRegister(1);
}
private int doRegister(int registrations) {
// adjustment to state
long adj = ((long)registrations << PARTIES_SHIFT) | registrations;
final Phaser parent = this.parent;
int phase;
for (;;) {
long s = state;
int counts = (int)s;
int parties = counts >>> PARTIES_SHIFT;
int unarrived = counts & UNARRIVED_MASK;
if (registrations > MAX_PARTIES - parties)//超出限制注册数
throw new IllegalStateException(badRegister(s));
else if ((phase = (int)(s >>> PHASE_SHIFT)) < 0)//阶段值出现负数,重新执行
break;
else if (counts != EMPTY) { //不是第一次注册,将参与者和位到达者次数加1
if (parent == null || reconcileState() == s) {//reconcileState后面详解。
if (unarrived == 0) //当前未到达数等于0,说明进入了下个节点,root等待进入下个阶段。
root.internalAwaitAdvance(phase, null);
else if (UNSAFE.compareAndSwapLong(this, stateOffset,
s, s + adj))//更新主状态
break;
}
}
else if (parent == null) {//没有父Phaser, 第一次注册,初始化状态值,将参与者和位到达者次数加1
long next = ((long)phase << PHASE_SHIFT) | adj;//组合初次注册状态值
if (UNSAFE.compareAndSwapLong(this, stateOffset, s, next))//更新主状态
break;
}
else {//有父Phaser
synchronized (this) { // 第一次子节点注册
if (state == s) { // 重新检查状态
parent.doRegister(1);//先注册父节点
do { // 当前的阶段值从父节点获取。
phase = (int)(root.state >>> PHASE_SHIFT);
// assert phase < 0 || (int)state == EMPTY;
} while (!UNSAFE.compareAndSwapLong //更新主状态值
(this, stateOffset, state,
((long)phase << PHASE_SHIFT) | adj));
break;
}
}
}
}
return phase;
}
代码看似复杂,实际主要是将参与者和未到达者次数加1.
doRegister方法中会调用reconcileState来调整状态,看下这个方法实现:
private long reconcileState() {
final Phaser root = this.root;
long s = state;
if (root != this) {
int phase, u, p;
// CAS root phase with current parties; possibly trip unarrived
while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
(int)(s >>> PHASE_SHIFT) &&
!UNSAFE.compareAndSwapLong
(this, stateOffset, s,
s = (((long)phase << PHASE_SHIFT) |
(s & PARTIES_MASK) |
((p = (int)s >>> PARTIES_SHIFT) == 0 ? EMPTY :
(u = (int)s & UNARRIVED_MASK) == 0 ? p : u))))
s = state;
}
return s;
}
这个方法要做的事情就是将当前Phaser和root Phaser的phase值调整为一致的。
arriveAndAwaitAdvance分析
到达并等待全员到齐
参与者只要有一个没执行这个方法,就阻塞,直到到达栅栏条件。
public int arriveAndAwaitAdvance() {
// Specialization of doArrive+awaitAdvance eliminating some reads/paths
final Phaser root = this.root;
for (;;) {
long s = (root == this) ? state : reconcileState();
int phase = (int)(s >>> PHASE_SHIFT);
int counts = (int)s;
int unarrived = (counts & UNARRIVED_MASK) - 1;
if (phase < 0)
return phase;
else if (counts == EMPTY || unarrived < 0) {//异常校验
if (reconcileState() == s)
throw new IllegalStateException(badArrive(s));
}
else if (UNSAFE.compareAndSwapLong(this, stateOffset, s,
s -= ONE_ARRIVAL)) {将参与者和未到达者次数减1
if (unarrived != 0)//还有未到达者,执行等待。
return root.internalAwaitAdvance(phase, null);
if (root != this)// unarrived ==0 但root不是当前对象,执行父对象等待
return parent.arriveAndAwaitAdvance();
//unarrived ==0 组装下阶段的状态值 并释放所有阻塞的节点
long n = s & PARTIES_MASK; //获取下个状态值得基本部分 这部分是只包含参与者数 其他位数数值为0
int nextUnarrived = (int)n >>> PARTIES_SHIFT;//获取下阶段未参与者数
if (onAdvance(phase, nextUnarrived))// 轮数增长钩子方法。
n |= TERMINATION_BIT;
else if (nextUnarrived == 0)
n |= EMPTY;
else
n |= nextUnarrived;//合并未参与者数
int nextPhase = (phase + 1) & MAX_PHASE;//获取下阶段数值(初始值0)
n |= (long)nextPhase << PHASE_SHIFT;//合并阶段数
if (!UNSAFE.compareAndSwapLong(this, stateOffset, s, n))//更新状态
return (int)(state >>> PHASE_SHIFT); // 状态修改失败,终止,返回阶段数
releaseWaiters(phase);//释放所有参与者
return nextPhase;//返回下阶段值
}
}
}
逻辑总结:
- 将参与者和未到达者次数减1
- 如果未到达者数不等于0,执行等待,等待结束后返回阶段值。
- 如果未到达者数等于0
- 如果当前是子Phaser,执行父Phaser的等待,等待结束后返回阶段值。
- 取出参与者数作为下阶段的位到达数,阶段值加1,组装下阶段状态值, 并释放所有阻塞的节点
internalAwaitAdvance分析
自旋,入队节点,阻塞等待全员到达开始下个阶段
private int internalAwaitAdvance(int phase, QNode node) {
releaseWaiters(phase-1); //确保旧的队列 干净
boolean queued = false; // 当节点入队后改为 true
int lastUnarrived = 0; // to increase spins upon change
int spins = SPINS_PER_ARRIVAL;
long s;
int p;
while ((p = (int)((s = state) >>> PHASE_SHIFT)) == phase) {//阶段值没发生变化 ,一直循环
if (node == null) { // spinning in noninterruptible mode
int unarrived = (int)s & UNARRIVED_MASK;
if (unarrived != lastUnarrived &&//当第一次执行 或 未到达数发生变化 且 未到达数小于CPU数时增加 自旋次数
(lastUnarrived = unarrived) < NCPU)
spins += SPINS_PER_ARRIVAL;
boolean interrupted = Thread.interrupted();
if (interrupted || --spins < 0) { //如果被打断 或自旋次数用完,创建一个不可打断的节点
node = new QNode(this, phase, false, false, 0L);
node.wasInterrupted = interrupted;
}
}
else if (node.isReleasable()) //如果可释放 终止
break;
else if (!queued) { // node 入队
AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;//获取当前队列,两个队列交换使用
QNode q = node.next = head.get();//获取头节点 并将node next指向头节点。 说明 node入队后放在头部
if ((q == null || q.phase == phase) &&//头节点是空的 或头结点阶段值等于当前阶段值
(int)(state >>> PHASE_SHIFT) == phase) //检查阶段值是否更改
queued = head.compareAndSet(q, node);//更新头节点
}
else {
try {
ForkJoinPool.managedBlock(node);//进入阻塞
} catch (InterruptedException ie) {
node.wasInterrupted = true;
}
}
}
if (node != null) {
if (node.thread != null)//节点线程不是空的,置为空
node.thread = null; // avoid need for 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
}
releaseWaiters(phase);//出队并释放所有等待节点
return p;
}
逻辑总结:
- 自旋,并根据未到达数和CPU数调整自旋次数
- 记录打断状态,创建不可打断不可超时节点,
- 如果可以释放,终止调用。否则入队 阻塞,再次检查是否可以释放, 不可释放 进入阻塞等待唤醒。
- 被唤醒 出队并 释放所有等待节点。
总结:Phaser 中long类型的状态值 不同位数 记录 未到达数,参与者数,阶段数,终止标识。执行过程包括 注册,到达,等待阶段增长 , 注册 将未到达数和参与者数1,到达将未到达数和参与者数1。 等待阶段增长 先到达的 自旋,入队等待队列,阻塞等待唤醒。 最后到达的初始化下轮状态值,唤醒等待队列中所有节点。arriveAndAwaitAdvance合并了 到达和等待阶段增长。