Jdk1.7 JUC源码增量解析(6)-Phaser
作者:大飞
- Phaser是jdk1.7提供的类似于CyclicBarrier和CountDownLatch的同步机制。
- 它支持更灵活的使用方式:1.使用过程中可以随时注册和注销参与者;2.不同于CyclicBarrier,分离出"到达"和"等待"机制;3.支持结束,默认情况下,当没有参与者的时候Phaser就结束了;4.支持层级Phaser结构;5.提供针对内部状态的监控方法;
- 先看一下内部结构:
/**
* 主状态,分为4部分:
*
* 未到达计数 -- 还没有到达栅栏的参与者计数。 (bits 0-15)
* parties -- 栅栏全部参与者的计数。 (bits 16-31)
* phase -- 栅栏当前所处的阶段 (bits 32-62)
* terminated -- 栅栏的结束标记 (bit 63 / sign)
*
* 一个没有注册参与者的phaser的主状态中会有0个参与者计数
* 和1个未到达计数。
*/
private volatile long state;
private static final int MAX_PARTIES = 0xffff;
private static final int MAX_PHASE = Integer.MAX_VALUE;
private static final int PARTIES_SHIFT = 16;
private static final int PHASE_SHIFT = 32;
private static final int UNARRIVED_MASK = 0xffff; // to mask ints
private static final long PARTIES_MASK = 0xffff0000L; // to mask longs
private static final long TERMINATION_BIT = 1L << 63;
// some special values
private static final int ONE_ARRIVAL = 1;
private static final int ONE_PARTY = 1 << PARTIES_SHIFT;
private static final int EMPTY = 1;
主状态这样设计(将状态封装到一个原子的long域)可以从两方面提高性能,一个是对状态的编解码简单高效、另一个是可以减小竞争窗口(空间)。
/**
* 当前phaser的父phaser, 如果没有父phaser,这个域为null。
*/
private final Phaser parent;
/**
* phaser树的根节点. 如果当前phaser不在一棵树内,这个域等于自身。
*/
private final Phaser root;
private final AtomicReference<QNode> evenQ;
private final AtomicReference<QNode> oddQ;
private AtomicReference<QNode> queueFor(int phase) {
return ((phase & 1) == 0) ? evenQ : oddQ;
}
再看下QNode这个类,先看下结构:
static final class QNode implements ForkJoinPool.ManagedBlocker {
final Phaser phaser;
final int phase;
final boolean interruptible;
final boolean timed;
boolean wasInterrupted;
long nanos;
long lastTime;
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.lastTime = timed ? System.nanoTime() : 0L;
thread = Thread.currentThread();
}
继续看下QNode中的方法,首先是isReleasable方法:
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;
}
再看下block方法:
public boolean block() {
if (isReleasable())
return true;
else if (!timed)
LockSupport.park(this);
else if (nanos > 0)
LockSupport.parkNanos(this, nanos);
return isReleasable();
}
- 通过一些示例来分析下主要功能源码。
首先看一个示例,使用方式类似于Count为1的CountDownLatch:
public static void main(String[] args) {
final Phaser phaser = new Phaser(1);
for(int i=0;i<10;i++){
phaser.register();
new Thread(new Runnable() {
@Override
public void run() {
phaser.arriveAndAwaitAdvance();
System.out.println(Thread.currentThread() +" start!!!!");
}
}).start();
}
try {
TimeUnit.SECONDS.sleep(5);
phaser.arriveAndDeregister();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
示例中首先构造了一个Phaser,我们先看下构造方法:
/**
* 创建一个没有初始参与者的phaser,默认没有父级phaser,初始
* phase值为0。如果有任何线程想要使用这个phaser,都必须先
* 注册这个phaser。
*/
public Phaser() {
this(null, 0);
}
/**
* 创建一个有初始参与者(未到达)数量的phaser,默认没有父级phaser,初始
* phase值为0。
*/
public Phaser(int parties) {
this(null, parties);
}
public Phaser(Phaser parent) {
this(parent, 0);
}
/**
* 创建一个有给定父级phaser和初始参与者(未到达)数量的phaser,
* 如果给定的父级phaser不为null,并且给定的参与者数量大于0,
* 当前的子phaser相当于注册了父phaser。
*/
public Phaser(Phaser parent, int parties) {
//parties不能超过65535
if (parties >>> PARTIES_SHIFT != 0)
throw new IllegalArgumentException("Illegal number of parties");
int phase = 0;
this.parent = parent;
if (parent != null) {
//如果父级Phaser不为空。
final Phaser root = parent.root;
this.root = root;
//共享父级的线程等待队列。
this.evenQ = root.evenQ;
this.oddQ = root.oddQ;
if (parties != 0)
//如果当前phaser的参与者不为0,那么注册一个参与者到父级,注意这里是一个。
phase = parent.doRegister(1);
}
else {
//如果父级为空。
//root就是自身,
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);
}
示例中接下来会在每次新建线程之前调用register方法来注册参与者,看下这个方法:
/**
* 添加一个新的未到达的参与者到当前phaser。如果当前正在onAdvance方法,
* 的执行过程中,这个方法会等待其完成再返回。如果当前phaser有父phaser,
* 并且当前phaser之前没有注册的参与者,phaser会注册到父phaser上。
* 如果当前phaser结束了,那么方法不会产生任何作用,并返回一个负数。
*/
public int register() {
return doRegister(1);
}
register内部调用的是doRegister,看下这个方法:
private int doRegister(int registrations) {
//调整主状态,将给定的数值加到总参与者和未到达参数者数量上。
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)
//如果phaser已经结束,那么直接退出循环。
break;
else if (counts != EMPTY) {
//如果不是第一个注册。
if (parent == null || reconcileState() == s) {
if (unarrived == 0)
// 如果当前未到达数量为0,说明需要进入下一阶段了,这里要等待一下root进入下一阶段。
root.internalAwaitAdvance(phase, null);
//否则原子更新主状态。
else if (UNSAFE.compareAndSwapLong(this, stateOffset,
s, s + adj))
break;
}
}
else if (parent == null) {
// 第一个root注册(没有父级)。
// 算出下一个主状态。
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;
}
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;
}
doRegister方法中,如果当前Phaser正在进入下一阶段过程中,需要等待这个过程完成,会调用internalAwaitAdvance方法,看下这个方法:
/** cpu核数 */
private static final int NCPU = Runtime.getRuntime().availableProcessors();
/**
* 单个参与者阻塞等待栅栏进入下一个阶段之前的自旋次数。
* 在多核处理器下,一次性完全的阻塞和唤醒一大批线程通常比较慢,
* 所以我们这里使用了一个可调整的自旋次数值在避免这种情况。
* 当一个参与者线程在internalAwaitAdvance方法中阻塞之前发现了
* 其他到达的线程,并且有cpu资源可用,那么这个参与者线程会在阻塞
* 之前自旋SPINS_PER_ARRIVAL或者更多次。
*/
static final int SPINS_PER_ARRIVAL = (NCPU < 2) ? 1 : 1 << 8;
private int internalAwaitAdvance(int phase, QNode node) {
releaseWaiters(phase-1); // 清空不用的等待线程队列(Treiber Stack)。
boolean queued = false; // 入队标识。
int lastUnarrived = 0; // 用于在发生变化时增加自旋次数。
int spins = SPINS_PER_ARRIVAL;
long s;
int p;
while ((p = (int)((s = state) >>> PHASE_SHIFT)) == phase) {
if (node == null) {
int unarrived = (int)s & UNARRIVED_MASK;
//如果未到达参与者数量发生了变化,且变化后的未到达数量小于cpu核数,需要增加自旋次数。
if (unarrived != lastUnarrived &&
(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()) // done or aborted
break;
else if (!queued) { // 将节点加入队列首部。
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);
}
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;
}
注意整个internalAwaitAdvance过程的前后都会清空一下当前不用的等待线程队列(两个奇偶队列交替使用),看下这个方法:
private void releaseWaiters(int phase) {
QNode q; // first element of queue
Thread t; // its thread
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.thread = null;
LockSupport.unpark(t);
}
}
}
internalAwaitAdvance中还可能会调用一个放弃等待的abortWait方法,看下:
private int abortWait(int phase) {
AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
for (;;) {
Thread t;
QNode q = head.get();
int p = (int)(root.state >>> PHASE_SHIFT);
if (q == null || ((t = q.thread) != null && q.phase == p))
return p;
if (head.compareAndSet(q, q.next) && t != null) {
q.thread = null;
LockSupport.unpark(t);
}
}
}
再回头看我们的示例,for循环中新建的线程在运行时会先调用arriveAndAwaitAdvance方法,然后会在这个方法上等待,直到主线程调用了arriveAndDeregister。看下arriveAndAwaitAdvance这个方法:
public int arriveAndAwaitAdvance() {
final Phaser root = this.root;
for (;;) {
//获取主状态
long s = (root == this) ? state : reconcileState();
//获取phase值
int phase = (int)(s >>> PHASE_SHIFT);
int counts = (int)s;
//获取当前未到达参与者计数,就是之前的未到达计数减1。
int unarrived = (counts & UNARRIVED_MASK) - 1;
if (phase < 0)
return phase; //如果当前phaser已经结束,退出。
else if (counts == EMPTY || unarrived < 0) {
if (reconcileState() == s)
throw new IllegalStateException(badArrive(s)); //非法状态。
}
//主状态中未到达参与者的计数减1。
else if (UNSAFE.compareAndSwapLong(this, stateOffset, s,
s -= ONE_ARRIVAL)) {
if (unarrived != 0)
//如果还有未到达的参与者,等待。
return root.internalAwaitAdvance(phase, null);
if (root != this)
//如果当前是子级Phaser,要等待父级进入下一阶段。
return parent.arriveAndAwaitAdvance();
long n = s & PARTIES_MASK; // base of next state
//这里算出来的是总参与者的数量。
int nextUnarrived = (int)n >>> PARTIES_SHIFT;
//调用onAdvance方法。
if (onAdvance(phase, nextUnarrived))
//如果onAdvance方法返回true,给主状态中设置结束标记。
n |= TERMINATION_BIT;
else if (nextUnarrived == 0)
//如果总参与者数量变为0,那么将主状态设置为没有参与者的特殊状态。
n |= EMPTY;
else
//否则,重置未到达参与者数量。
n |= nextUnarrived;
//算出下一个phase值。
int nextPhase = (phase + 1) & MAX_PHASE;
//设置到主状态上。
n |= (long)nextPhase << PHASE_SHIFT;
//原子更新主状态。
if (!UNSAFE.compareAndSwapLong(this, stateOffset, s, n))
//如果发生竞争,返回phase值,如果当前phaser结束,返回负数。
return (int)(state >>> PHASE_SHIFT); // terminated
//清空上一阶段使用的线程等待队列。
releaseWaiters(phase);
//最后返回上面算出来的nextPhase值。
return nextPhase;
}
}
}
看一下arriveAndAwaitAdvance方法中调用的onAdvance方法:
protected boolean onAdvance(int phase, int registeredParties) {
return registeredParties == 0;
}
回到示例的最后,主线程休眠5秒中,然后调用了arriveAndDeregister方法,看下这个方法:
public int arriveAndDeregister() {
return doArrive(true);
}
这个方法表示一个参与者到达栅栏,并且将自己从phaser上注销。内部调用了doArrive方法:
private int doArrive(boolean deregister) {
int adj = deregister ? ONE_ARRIVAL|ONE_PARTY : ONE_ARRIVAL;
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 (root == this || reconcileState() == s)
throw new IllegalStateException(badArrive(s));
}
else if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s-=adj)) {
if (unarrived == 0) {
long n = s & PARTIES_MASK; // base of next state
int nextUnarrived = (int)n >>> PARTIES_SHIFT;
if (root != this)
//这里注意下:如果当前子phaser中没有参与者了,就要于从父phaser中将当前子phaser注销。
return parent.doArrive(nextUnarrived == 0);
if (onAdvance(phase, nextUnarrived))
n |= TERMINATION_BIT;
else if (nextUnarrived == 0)
n |= EMPTY;
else
n |= nextUnarrived;
n |= (long)((phase + 1) & MAX_PHASE) << PHASE_SHIFT;
UNSAFE.compareAndSwapLong(this, stateOffset, s, n);
releaseWaiters(phase);
}
return phase;
}
}
}
再看一个示例,使用方式类似于Count为N的CountDownLatch:
public static void main(String[] args) {
final Phaser phaser = new Phaser();
for(int i=0;i<10;i++){
phaser.register();
new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
System.out.println(Thread.currentThread() +" is ready!");
phaser.arriveAndAwaitAdvance();
System.out.println(Thread.currentThread() +" start!!!!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
继续看一个示例,和第一个示例差不多,但有一点区别:第一个示例中线程只执行了一次逻辑,现在要求线程执行若干次逻辑:
public static void main(String[] args) {
final Phaser phaser = new Phaser(1){
protected boolean onAdvance(int phase, int registeredParties) {
System.out.println("now phase is " + phase);
return phase >= 5 || registeredParties == 0;
}
};
for(int i=0;i<5;i++){
phaser.register();
final int time = i;
new Thread(new Runnable() {
@Override
public void run() {
do{
phaser.arriveAndAwaitAdvance();
System.out.println(Thread.currentThread() +" start-"+time+"!!!!");
}while(!phaser.isTerminated());
}
}).start();
}
try {
TimeUnit.SECONDS.sleep(5);
System.out.println("arriveAndDeregister...");
phaser.arriveAndDeregister();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
示例输出如下:
arriveAndDeregister...
now phase is 0
Thread[Thread-4,5,main] start-4!!!!
Thread[Thread-1,5,main] start-1!!!!
Thread[Thread-0,5,main] start-0!!!!
Thread[Thread-2,5,main] start-2!!!!
Thread[Thread-3,5,main] start-3!!!!
now phase is 1
Thread[Thread-0,5,main] start-0!!!!
Thread[Thread-4,5,main] start-4!!!!
Thread[Thread-2,5,main] start-2!!!!
Thread[Thread-3,5,main] start-3!!!!
Thread[Thread-1,5,main] start-1!!!!
now phase is 2
Thread[Thread-1,5,main] start-1!!!!
Thread[Thread-3,5,main] start-3!!!!
Thread[Thread-2,5,main] start-2!!!!
Thread[Thread-4,5,main] start-4!!!!
Thread[Thread-0,5,main] start-0!!!!
now phase is 3
Thread[Thread-0,5,main] start-0!!!!
Thread[Thread-3,5,main] start-3!!!!
Thread[Thread-1,5,main] start-1!!!!
Thread[Thread-2,5,main] start-2!!!!
Thread[Thread-4,5,main] start-4!!!!
now phase is 4
Thread[Thread-4,5,main] start-4!!!!
Thread[Thread-0,5,main] start-0!!!!
Thread[Thread-1,5,main] start-1!!!!
Thread[Thread-3,5,main] start-3!!!!
Thread[Thread-2,5,main] start-2!!!!
now phase is 5
Thread[Thread-2,5,main] start-2!!!!
Thread[Thread-3,5,main] start-3!!!!
Thread[Thread-4,5,main] start-4!!!!
Thread[Thread-0,5,main] start-0!!!!
Thread[Thread-1,5,main] start-1!!!!
- 最后,看一下示例中未涉及到的代码。
private static int unarrivedOf(long s) {
int counts = (int)s;
return (counts == EMPTY) ? 0 : counts & UNARRIVED_MASK;
}
private static int partiesOf(long s) {
return (int)s >>> PARTIES_SHIFT;
}
private static int phaseOf(long s) {
return (int)(s >>> PHASE_SHIFT);
}
private static int arrivedOf(long s) {
int counts = (int)s;
return (counts == EMPTY) ? 0 :
(counts >>> PARTIES_SHIFT) - (counts & UNARRIVED_MASK);
}
这组方法可以从主状态中获取各个状态,是一组"拆包"方法。在具体功能方法内部可能不会调用这些方法,而是手工内联进去。
private String badArrive(long s) {
return "Attempted arrival of unregistered party for " +
stateToString(s);
}
private String badRegister(long s) {
return "Attempt to register more than " +
MAX_PARTIES + " parties for " + stateToString(s);
}
private String stateToString(long s) {
return super.toString() +
"[phase = " + phaseOf(s) +
" parties = " + partiesOf(s) +
" arrived = " + arrivedOf(s) + "]";
}
这badArrice和badRegister方法用于在逻辑中出现非法参与注册情况时,提供提示消息。stateToString方法将state转化为易懂的字符串形式,用于支持前面两个方法和toString方法。
public int bulkRegister(int parties) {
if (parties < 0)
throw new IllegalArgumentException();
if (parties == 0)
return getPhase();
return doRegister(parties);
}
public final int getPhase() {
return (int)(root.state >>> PHASE_SHIFT);
}
相对于register的批量注册方法。
public int arrive() {
return doArrive(false);
}
和arriveAndDeregister类似,只是不会注销当前参与者。
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)
return root.internalAwaitAdvance(phase, null);
return p;
}
等待phase值表示的阶段,如果当前phase和给定的phase不一致,直接返回当前的phase值。
public int awaitAdvanceInterruptibly(int phase)
throws InterruptedException {
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) {
QNode node = new QNode(this, phase, true, false, 0L);
p = root.internalAwaitAdvance(phase, node);
if (node.wasInterrupted)
throw new InterruptedException();
}
return p;
}
awaitAdvance方法逻辑一样,但支持中断。
public int awaitAdvanceInterruptibly(int phase,
long timeout, TimeUnit unit)
throws InterruptedException, TimeoutException {
long nanos = unit.toNanos(timeout);
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) {
QNode node = new QNode(this, phase, true, true, nanos);
p = root.internalAwaitAdvance(phase, node);
if (node.wasInterrupted)
throw new InterruptedException();
else if (p == phase)
throw new TimeoutException();
}
return p;
}
awaitAdvance方法逻辑一样,但支持中断和超时。
public void forceTermination() {
// Only need to change root state
final Phaser root = this.root;
long s;
while ((s = root.state) >= 0) {
//给主状态中添加结束标记。
if (UNSAFE.compareAndSwapLong(root, stateOffset,
s, s | TERMINATION_BIT)) {
//清空奇偶线程等待队列。
releaseWaiters(0);
releaseWaiters(1);
return;
}
}
}
最后看一些支持监控的方法:
public final int getPhase() {
return (int)(root.state >>> PHASE_SHIFT);
}
public int getRegisteredParties() {
return partiesOf(state);
}
public int getArrivedParties() {
return arrivedOf(reconcileState());
}
public int getUnarrivedParties() {
return unarrivedOf(reconcileState());
}
public Phaser getParent() {
return parent;
}
public Phaser getRoot() {
return root;
}
public boolean isTerminated() {
return root.state < 0L;
}
OK,JDK1.7 Phaser的代码解析完毕!
参见:Jdk1.6 JUC源码解析(9)-CountDownLatch
参见:Jdk1.6 JUC源码解析(11)-CyclicBarrier
参见:Jdk1.7 JUC源码增量解析(5)-ForkJoin-ForkJoin框架其他过程及方法