1.使用示例
public class MyPhaser extends Phaser {
//定义结束阶段.这里是完成3个阶段以后结束
private int phaseToTerminate = 2;
@Override
protected boolean onAdvance(int phase, int registeredParties) {
System.out.println("*第"+phase+"阶段完成*");
//到达结束阶段,或者还没到结束阶段但是party为0,都返回true,结束phaser
return phase==phaseToTerminate || registeredParties==0;
}
public static class Swimmer implements Runnable{
private Phaser phaser;
public Swimmer(Phaser phaser) {
this.phaser = phaser;
}
@Override
public void run() {
/*
* 从这里到第一个phaser.arriveAndAwaitAdvance()是第一阶段做的事
*/
try {
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("游泳选手-"+Thread.currentThread().getName()+":已到达赛场");
phaser.arriveAndAwaitAdvance();
/*
* 从这里到第二个phaser.arriveAndAwaitAdvance()是第二阶段做的事
*/
try {
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("游泳选手-"+Thread.currentThread().getName()+":已准备好");
phaser.arriveAndAwaitAdvance();
/*
* 从这里到第三个phaser.arriveAndAwaitAdvance()是第三阶段做的事
*/
try {
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("游泳选手-"+Thread.currentThread().getName()+":完成比赛");
phaser.arriveAndAwaitAdvance();
}
}
public static void main(String[] args) {
int swimmerNum = 6;
MyPhaser phaser = new MyPhaser();
//注册主线程,用于控制phaser何时开始第二阶段
phaser.register();
for(int i=0; i
结果:
游泳选手-swimmer4:已到达赛场
游泳选手-swimmer2:已到达赛场
游泳选手-swimmer5:已到达赛场
游泳选手-swimmer3:已到达赛场
游泳选手-swimmer0:已到达赛场
游泳选手-swimmer1:已到达赛场
*第0阶段完成*
游泳选手-swimmer2:已准备好
游泳选手-swimmer0:已准备好
游泳选手-swimmer4:已准备好
游泳选手-swimmer3:已准备好
游泳选手-swimmer5:已准备好
游泳选手-swimmer1:已准备好
*第1阶段完成*
游泳选手-swimmer4:完成比赛
游泳选手-swimmer2:完成比赛
游泳选手-swimmer1:完成比赛
游泳选手-swimmer0:完成比赛
游泳选手-swimmer5:完成比赛
游泳选手-swimmer3:完成比赛
*第2阶段完成*
===== 比赛结束 =====
2.官方文档
A reusable synchronization barrier, similar in functionality to
CyclicBarrier and CountDownLatch but supporting more flexible
usage.
Registration. Unlike the case for other barriers, the number of
parties registered to synchronize on a phaser may vary over time.
Tasks may be registered at any time (using methods register(),
bulkRegister(int), or forms of constructors establishing initial
numbers of parties), and optionally deregistered upon any arrival
(using arriveAndDeregister()). As is the case with most basic
synchronization constructs, registration and deregistration affect
only internal counts; they do not establish any further internal
bookkeeping, so tasks cannot query whether they are registered.
(However, you can introduce such bookkeeping by subclassing this
class.)
可重用的同步barrier,功能类似于CyclicBarrier和CountDownLatch,但自此更灵活的使用。
注册Registration。与其他barriers不同,在phaser上同步注册的数量可能会时间而变化。可以随时注册任务(使用方法register(), bulkRegister(int)或构造器初始化),并且可在任何arrival注销任务(使用arriveAndDeregister())。与大多数基本同步结构一样,注册和注销仅影响内部计数;没有建立任何进一步的簿记,因此任务无法查询它们是否已注册。(但是可以通过继承该类来实现这样的簿记。)
Synchronization. Like a CyclicBarrier, a Phaser may be repeatedly
awaited. Method arriveAndAwaitAdvance() has effect analogous to
CyclicBarrier.await. Each generation of a phaser has an associated
phase number. The phase number starts at zero, and advances
when all parties arrive at the phaser, wrapping around to zero after
reaching Integer.MAX_VALUE. The use of phase numbers enables
independent control of actions upon arrival at a phaser and upon
awaiting others, via two kinds of methods that may be invoked by
any registered party:
1)Arrival. Methods arrive() and arriveAndDeregister() record
arrival. These methods do not block, but return an associated
arrival phase number; that is, the phase number of the phaser to
which the arrival applied. When the final party for a given phase
arrives, an optional action is performed and the phase advances.
These actions are performed by the party triggering a phase
advance, and are arranged by overriding method onAdvance(int,
int), which also controls termination. Overriding this method is
similar to, but more flexible than, providing a barrier action to a
CyclicBarrier.
2)Waiting. Method awaitAdvance(int) requires an argument
indicating an arrival phase number, and returns when the phaser
advances to (or is already at) a different phase. Unlike similar
constructions using CyclicBarrier, method awaitAdvance continues
to wait even if the waiting thread is interrupted. Interruptible and
timeout versions are also available, but exceptions encountered
while tasks wait interruptibly or with timeout do not change the
state of the phaser. If necessary, you can perform any associated
recovery within handlers of those exceptions, often after invoking
forceTermination. Phasers may also be used by tasks executing in
a ForkJoinPool, which will ensure sufficient parallelism to execute
tasks when others are blocked waiting for a phase to advance.
同步Synchronization。与CyclicBarrier一样,Phaser可反复调用await。方法arrivalAndAwaitAdvance()具有类似于CyclicBarrier.await的效果。phaser的每一代都有一个关联的phaser数。phaser数从0开始,并在各方都到达phaser的时候前进,在达到Integer.MAX_VALUE后回绕到零。使用phaser数可以通过任何注册方调用两种方法独立控制到达arrival phaser的行为以及awaiting其他相关方的行为:
- 1)到达Arrival
方法arrive() 和arriveAndDeregister()记录到达。这些方法不会阻塞,并会返回一个相关的到达phase数,也即arrival应用的phase数。当最后一个相关方到达,执行可选的操作然后phase前进。这些行为由触发phase前进的相关方执行,并通过覆写onAdvance(int, int)来实现,该方法也控制终止。覆写该方法类似给CyclicBarrier提供一个barrier action,但是更灵活。 - 2)等待Waiting
awaitAdvance(int)需要一个指示到达phase数的参数,并在phaser前进到(或已经到了)另一个不同的phase时返回。与使用CyclicBarrier的类似结构不同,方法awaitAdvance在等待的线程被中断的情况下也会继续等待。也提供中断和超时版本,但在任务中断或超时等待时遇到的异常不会更改移phaser的状态。如有必要,可以在调用forceTermination之后,在这些异常的处理程序中执行任何相关的恢复。在ForkJoinPool中执行的任务也可以使用Phasers,当其他相关方阻塞等待phase前进时,Phasers将确保执行任务时有足够的并行性。
Termination. A phaser may enter a termination state, that may be
checked using method isTerminated(). Upon termination, all
synchronization methods immediately return without waiting for
advance, as indicated by a negative return value. Similarly,
attempts to register upon termination have no effect. Termination is
triggered when an invocation of onAdvance returns true. The
default implementation returns true if a deregistration has caused
the number of registered parties to become zero. As illustrated
below, when phasers control actions with a fixed number of
iterations, it is often convenient to override this method to cause
termination when the current phase number reaches a threshold.
Method forceTermination() is also available to abruptly release
waiting threads and allow them to terminate.
Tiering. Phasers may be tiered (i.e., constructed in tree structures)
to reduce contention. Phasers with large numbers of parties that
would otherwise experience heavy synchronization contention
costs may instead be set up so that groups of sub-phasers share a
common parent. This may greatly increase throughput even though
it incurs greater per-operation overhead.
In a tree of tiered phasers, registration and deregistration of child
phasers with their parent are managed automatically. Whenever
the number of registered parties of a child phaser becomes non-
zero (as established in the Phaser(Phaser,int) constructor,
register(), or bulkRegister(int)), the child phaser is registered with
its parent. Whenever the number of registered parties becomes
zero as the result of an invocation of arriveAndDeregister(), the
child phaser is deregistered from its parent.
终止Termination。phaser可能会进入终止状态,使用方法isTerminated()来检查。终止时,所有同步方法立即返回,返回负值。在终止时注册也没有任何效果。当调用onAdvance返回true时就会触发终止。默认实现在注销导致注册的相关方数量降为0时会返回true。方法forceTermination()也可用于突然释放等待线程并让它们终止。
分层Tiering。Phasers可以分层(例如以树的结构)以减少争用。巨大数量的相关方会导致Phaser巨大的同步竞争成本,可以使用共享同一个父亲的子phasers组来代替。这可以极大地提高吞吐量即使单个操作的开销更高了。
在分层的phasers树中,子phasers与其父亲的注册与注销是自动管理的。当子phaser注册的数量不为0时(构造器 register() bulkRegister(int)),会注册到其父亲中去。如果子phaser注册的数量为0(arriveAndDeregister()),子phaser会从父亲中注销掉。
Monitoring. While synchronization methods may be invoked only by
registered parties, the current state of a phaser may be monitored
by any caller. At any given moment there are
getRegisteredParties() parties in total, of which getArrivedParties()
have arrived at the current phase (getPhase()). When the
remaining (getUnarrivedParties()) parties arrive, the phase
advances. The values returned by these methods may reflect
transient states and so are not in general useful for synchronization
control. Method toString() returns snapshots of these state queries
in a form convenient for informal monitoring.
监测Monitoring。同步方法只能由注册方调用,但是调用者可以监测phaser的当前状态。
- getRegisteredParties()返回注册总数
- getArrivedParties()当前到达的数量
- getPhase()当前phase
- getUnarrivedParties()还有多少没有到达当前phase
Sample usages:
A Phaser may be used instead of a CountDownLatch to control
a one-shot action serving a variable number of parties. The
typical idiom is for the method setting this up to first register,
then start the actions, then deregister, as in
使用示例:
Phaser用来代替CountDownLatch用于控制一次性操作的可变数量的相关方。惯用法是:
- 首先注册
- 然后执行操作
- 然后取消注册
void runTasks(List tasks) {
final Phaser phaser = new Phaser(1); // "1" to register self
// create and start threads
for (final Runnable task : tasks) {
phaser.register();
new Thread() {
public void run() {
phaser.arriveAndAwaitAdvance(); // await all creation
task.run();
}
}.start();
}
// allow threads to start and deregister self
phaser.arriveAndDeregister();
}
使一组线程重复执行给定次数迭代操作的一种方法是覆盖onAdvance:
void startTasks(List tasks, final int iterations) {
final Phaser phaser = new Phaser() {
protected boolean onAdvance(int phase, int registeredParties) {
return phase >= iterations || registeredParties == 0;
}
};
phaser.register();
for (final Runnable task : tasks) {
phaser.register();
new Thread() {
public void run() {
do {
task.run();
phaser.arriveAndAwaitAdvance();
} while (!phaser.isTerminated());
}
}.start();
}
phaser.arriveAndDeregister(); // deregister self, don't wait
}
如果主线程必须等待终止,可以重新注册并执行一个类似的循环:
// ...
phaser.register();
while (!phaser.isTerminated())
phaser.arriveAndAwaitAdvance();
如果确定phase不会回绕Integer.MAX_VALUE,如下结构可用于等待特定phase数。
void awaitPhase(Phaser phaser, int phase) {
int p = phaser.register(); // assumes caller not already registered
while (p < phase) {
if (phaser.isTerminated())
// ... deal with unexpected termination
else
p = phaser.arriveAndAwaitAdvance();
}
phaser.arriveAndDeregister();
}
要使用phasers树创建一组n个任务,可以使用如下形式代码。假设Task类有一个构造器接受Phaser。调用build(new Task[n], 0, n, new Phaser())后,这些任务就可以启动,例如可以提交到线程池中:
void build(Task[] tasks, int lo, int hi, Phaser ph) {
if (hi - lo > TASKS_PER_PHASER) {
for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
int j = Math.min(i + TASKS_PER_PHASER, hi);
build(tasks, i, j, new Phaser(ph));
}
} else {
for (int i = lo; i < hi; ++i)
tasks[i] = new Task(ph);
// assumes new Task(ph) performs ph.register()
}
}
TASKS_PER_PHASER的最佳值主要取决于同步速率的期望。 低至4的值可能适用于极小的每phase任务量(因此高速率),或者对于极大的任务量而言可能高达数百。
3.构造器
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) {
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;
this.evenQ = new AtomicReference();
this.oddQ = new AtomicReference();
}
this.state = (parties == 0) ? (long)EMPTY :
((long)phase << PHASE_SHIFT) |
((long)parties << PARTIES_SHIFT) |
((long)parties);
}
如果parent为null:
- root指向自己
- evenQ, oddQ各初始化为new AtomicReference
()
会初始化state为:
- unarrived的数量为parties
- parties的数量为parties
- phase为0
3.1 相关的域
/**
* The parent of this phaser, or null if none
*/
private final Phaser parent;
/**
* The root of phaser tree. Equals this if not in a tree.
*/
private final Phaser root;
/**
* Heads of Treiber stacks for waiting threads. To eliminate
* contention when releasing some threads while adding others, we
* use two of them, alternating across even and odd phases.
* Subphasers share queues with root to speed up releases.
*/
private final AtomicReference evenQ;
private final AtomicReference oddQ;
如果不在phaser树中,则root指向自己。
evenQ和oddQ是等待线程Treiber栈的头部。为了消除释放某些线程的同时增加某些线程,使用两个队列,在偶数和奇数phases交替。子phasers与root共享队列以加速释放。
3.2 QNode
构造器:
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();
}
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) {
nanos = deadline - System.nanoTime();
}
if (nanos <= 0L) {
thread = null;
return true;
}
}
return false;
}
在如下四种情况时,isReleasable()返回true:
- thread为null
- phaser的phase不为QNode的phase
- 发生了中断,并且当前QNode可以中断
- 超时时间到了
public boolean block() {
if (isReleasable())
return true;
else if (!timed)
LockSupport.park(this);
else if (nanos > 0L)
LockSupport.parkNanos(this, nanos);
return isReleasable();
}
- 如果isReleasable()则直接返回true
- 如果QNode没有设置超时,则阻塞当前线程
- 如果设置了超时,则阻塞指定的时间
- 返回isReleasable()
3.3 关于state分析
/**
* Primary state representation, holding four bit-fields:
*
* unarrived -- the number of parties yet to hit barrier (bits 0-15)
* parties -- the number of parties to wait (bits 16-31)
* phase -- the generation of the barrier (bits 32-62)
* terminated -- set if barrier is terminated (bit 63 / sign)
*
* Except that a phaser with no registered parties is
* distinguished by the otherwise illegal state of having zero
* parties and one unarrived parties (encoded as EMPTY below).
*
* To efficiently maintain atomicity, these values are packed into
* a single (atomic) long. Good performance relies on keeping
* state decoding and encoding simple, and keeping race windows
* short.
*
* All state updates are performed via CAS except initial
* registration of a sub-phaser (i.e., one with a non-null
* parent). In this (relatively rare) case, we use built-in
* synchronization to lock while first registering with its
* parent.
*
* The phase of a subphaser is allowed to lag that of its
* ancestors until it is actually accessed -- see method
* reconcileState.
*/
private volatile long state;
state分为四个部分:
- unarrived —— 还没有到达barrier的相关方数量(0-15位)
- parties —— 等待的相关方数量 (16 - 31位)
- phase —— barrier代 (32-62位)
- terminated —— 如果终止则置位(63位/符号位)
没有注册任何相关方的phaser要与如下非法状态区分开,即0个相关方并且有一个未到达的相关方的非法状态(编码为EMPTY)。
为了有效地维持原子性,这些值被包裹在一个单一的long里面。良好的性能依赖于简单的状态解码和编码,并且保持短的竞争窗口。
除了子phaser初始注册外(当首次向父亲注册时使用内置同步锁),所有状态更新都通过CAS执行。
允许子phaser的phase滞后于其祖先的,直到它实际被访问为止——参考方法reconcileState
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 COUNTS_MASK = 0xffffffffL;
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 ONE_DEREGISTER = ONE_ARRIVAL|ONE_PARTY;
private static final int EMPTY = 1;
// The following unpacking methods are usually manually inlined
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);
}
4.register
/**
* Adds a new unarrived party to this phaser. If an ongoing
* invocation of {@link #onAdvance} is in progress, this method
* may await its completion before returning. If this phaser has
* a parent, and this phaser previously had no registered parties,
* this child phaser is also registered with its parent. If
* this phaser is terminated, the attempt to register has
* no effect, and a negative value is returned.
*
* @return the arrival phase number to which this registration
* applied. If this value is negative, then this phaser has
* terminated, in which case registration has no effect.
* @throws IllegalStateException if attempting to register more
* than the maximum supported number of parties
*/
public int register() {
return doRegister(1);
}
为此phaser添加一个新的未到达的相关方,如果正在调用onAdvance(int,int),则会等待其完成。如果该phaser有父亲,并且之前没有任何注册方,那么该子phaser也会注册到父亲中。如果该phaser终止了,那么尝试注册没有任何效果,并返回以负值。
private int doRegister(int registrations) {
// adjustment to state
long adjust = ((long)registrations << PARTIES_SHIFT) | registrations;
final Phaser parent = this.parent;
int phase;
for (;;) {
long s = (parent == null) ? state : reconcileState();
int counts = (int)s;
int parties = counts >>> PARTIES_SHIFT;
int unarrived = counts & UNARRIVED_MASK;
if (registrations > MAX_PARTIES - parties)
throw new IllegalStateException(badRegister(s));
phase = (int)(s >>> PHASE_SHIFT);
if (phase < 0)
break;
if (counts != EMPTY) { // not 1st registration
if (parent == null || reconcileState() == s) {
if (unarrived == 0) // wait out advance
root.internalAwaitAdvance(phase, null);
else if (UNSAFE.compareAndSwapLong(this, stateOffset,
s, s + adjust))
break;
}
}
else if (parent == null) { // 1st root registration
long next = ((long)phase << PHASE_SHIFT) | adjust;
if (UNSAFE.compareAndSwapLong(this, stateOffset, s, next))
break;
}
else {
synchronized (this) { // 1st sub registration
if (state == s) { // recheck under lock
phase = parent.doRegister(1);
if (phase < 0)
break;
// finish registration whenever parent registration
// succeeded, even when racing with termination,
// since these are part of the same "transaction".
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;
}
5.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);
if (phase < 0)
return phase;
int counts = (int)s;
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
if (UNSAFE.compareAndSwapLong(this, stateOffset, s,
s -= ONE_ARRIVAL)) {
if (unarrived > 1)
return root.internalAwaitAdvance(phase, null);
if (root != this)
return parent.arriveAndAwaitAdvance();
long n = s & PARTIES_MASK; // base of next state
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;
n |= (long)nextPhase << PHASE_SHIFT;
if (!UNSAFE.compareAndSwapLong(this, stateOffset, s, n))
return (int)(state >>> PHASE_SHIFT); // terminated
releaseWaiters(phase);
return nextPhase;
}
}
}
到达该phaser并等待其他线程。与awaitAdvance(arrive())等效。如果需要中断和超时机制,可以使用awaitAdvance其他形式(awaitAdvanceInterruptibly)进行类似组合。
未注册方调用该方法是错误的。但是,此错误可能仅在此phaser的某些后续操作时导致IllegalStateException。
返回值:到达的phase数,如果终止,则返回(负)当前phase
该方法有三个关键点:
- 当所有相关方还未到达该phaser时,调用root.internalAwaitAdvance(phase, null)
- 当所有相关方到达时,需要判断是否进行终止onAdvance(phase, nextUnarrived)
- 到达后,并且还未到达终止状态时,此时phase向前进1,并且调用releaseWaiters(phase)
5.1 onAdvance
是个 protected方法,子类可覆盖。
protected boolean onAdvance(int phase, int registeredParties) {
return registeredParties == 0;
}
用于在phase即将前进时执行操作,并控制终止。当最后一方到来时调用该方法(其他等待方都处于休眠状态)。如果此方法返回true,则将设置状态为终止状态,随后的isTerminated()调用将返回true。该方法抛出的任何未受查异常或错误会传递到推进该phaser的相关方,并导致最终不会前进。
在onAdvance中调用arrival registration和waiting方法的影响是未确定的。
如果该phaser是分层phasers的成员,则在每次前进时仅调用root phaser的onAdvance。
默认情况支持最常见的使用场景,当注册方数量因为调用arrivalAndDeregister变为0时,此方法返回true。可以禁用此行为,为了在将来注册时重新启用,实现方式是重写该方法并始终返回false。
5.2 internalAwaitAdvance
private int internalAwaitAdvance(int phase, QNode node) {
// assert root == this;
releaseWaiters(phase-1); // ensure old queue clean
boolean queued = false; // true when node is enqueued
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 &&
(lastUnarrived = unarrived) < NCPU)
spins += SPINS_PER_ARRIVAL;
boolean interrupted = Thread.interrupted();
if (interrupted || --spins < 0) { // need node to record intr
node = new QNode(this, phase, false, false, 0L);
node.wasInterrupted = interrupted;
}
}
else if (node.isReleasable()) // done or aborted
break;
else if (!queued) { // push onto queue
AtomicReference 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;
}
几个关键点:
- 如果还未到达的线程比NCPU少,则会自旋一段时间
- 自旋过后,就会新建QNode结点,如果没有加入到队列中,则加入到队列头部(栈),然后就会调用QNode.block()方法阻塞。
5.3 releaseWaiters
private void releaseWaiters(int phase) {
QNode q; // first element of queue
Thread t; // its thread
AtomicReference 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);
}
}
}
会释放等待在QNode中的线程,并将每个结点的q.thread置为null。
为什么要两个QNode队列?
当最后一个线程到达phaser的当前phase时,会releaseWaiters释放在当前phase阻塞的所有线程,并且会前进到下一个phase。如果用的是同一个QNode队列,此时释放和前进到下一个phase会争用同一个队列。所以分开对于phase前进的情况比较好地避免了争用的情况。
6.arriveAndDeregister
private static final int ONE_DEREGISTER = ONE_ARRIVAL|ONE_PARTY;
public int arriveAndDeregister() {
return doArrive(ONE_DEREGISTER);
}
到达phaser并且从中注销,不用等其他线程到达。注销减少了parties。如果该phaser有父亲,并且注销使得其parites减为0,则也从父亲中注销该phaser。
private int doArrive(int adjust) {
final Phaser root = this.root;
for (;;) {
long s = (root == this) ? state : reconcileState();
int phase = (int)(s >>> PHASE_SHIFT);
if (phase < 0)
return phase;
int counts = (int)s;
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s-=adjust)) {
if (unarrived == 1) {
long n = s & PARTIES_MASK; // base of next state
int nextUnarrived = (int)n >>> PARTIES_SHIFT;
if (root == this) {
if (onAdvance(phase, nextUnarrived))
n |= TERMINATION_BIT;
else if (nextUnarrived == 0)
n |= EMPTY;
else
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
UNSAFE.compareAndSwapLong(this, stateOffset, s, n);
releaseWaiters(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);
}
return phase;
}
}
}
7.总结
- 1)核心是通过volatile long state + LockSupport.park/unpark实现的。当到达phaser其他线程没有到达时则阻塞,最后一个到达的会唤醒阻塞在QNode中线程
- 2)使用两个QNode队列,编码了phaser的phase前进时,避免了releaseWaiters释放在当前phase阻塞的QNode队列中所有线程以及在下一个phase阻塞加入QNode队列时产生的对QNode队列的争用。线程也只会在root结点上被封装进QNode结点入栈(或者叫QNode队列)
- 3)(本文并未研究)支持分层phaser树,分摊并发的压力。每个phaser在初始时(被第一个线程注册时)以当前线程向其父phaser注册的方式与其父phaser建立联系,当此phaser上的线程都到达了,再以当前线程(最后一个抵达的线程)通知其父phaser,自己这边OK了,每个phaser都以同样的方式通知其父phaser,最后到达root phaser,开始唤醒睡在栈里(QNode链表)的线程,准备进入下一阶段。
参考
- 【JUC源码解析】Phaser