@eric1989
2017-05-30T23:25:01.000000Z
字数 33773
阅读 1504
并发源码阅读
final void externalPush(ForkJoinTask<?> task)
{
WorkQueue[] ws;
WorkQueue q;
int m;
int r = ThreadLocalRandom.getProbe();
int rs = runState;
if ((ws = workQueues) != null && (m = (ws.length - 1)) >= 0 && (q = ws[m & r & SQMASK]) != null && r != 0 && rs > 0 && U.compareAndSwapInt(q, QLOCK, 0, 1))
{
ForkJoinTask<?>[] a;
int am, n, s;
if ((a = q.array) != null && (am = a.length - 1) > (n = (s = q.top) - q.base))
{
int j = ((am & s) << ASHIFT) + ABASE;
U.putOrderedObject(a, j, task);
U.putOrderedInt(q, QTOP, s + 1);
U.putIntVolatile(q, QLOCK, 0);
if (n <= 1)
signalWork(ws, q);
return;
}
U.compareAndSwapInt(q, QLOCK, 1, 0);
}
//全量的提交执行
externalSubmit(task);
}
主要完成几个工作
private void externalSubmit(ForkJoinTask<?> task)
{
//获得线程内的随机数,这个没什么好讲的。
int r; // initialize caller's probe
if ((r = ThreadLocalRandom.getProbe()) == 0)
{
ThreadLocalRandom.localInit();
r = ThreadLocalRandom.getProbe();
}
for (;;)
{
WorkQueue[] ws;
WorkQueue q;
int rs, m, k;
boolean move = false;
if ((rs = runState) < 0)
{
tryTerminate(false, false); // help terminate
throw new RejectedExecutionException();
}
//如果发现
//1.线程池尚未启动
//2.工作队列尚未初始化
//3.工作队列长度为0
//三个条件任意存在,则尝试执行初始化工作
else if ((rs & STARTED) == 0 || // initialize
((ws = workQueues) == null || (m = ws.length - 1) < 0))
{
int ns = 0;
rs = lockRunState();
try
{
if ((rs & STARTED) == 0)
{
U.compareAndSwapObject(this, STEALCOUNTER, null, new AtomicLong());
// create workQueues array with size a power of two
//config包含了ForkJoinPool的配置信息。是一个int数字。其中低16位bit用于表达系统整体的并发数。第17位bit用于表达模式。先进先出还是后进先出。先进先出是队列,后进先出是栈。
int p = config & SMASK; // ensure at least 2 slots
int n = (p > 1) ? p - 1 : 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
n = (n + 1) << 1;
//上面的算法是一个固定的快速算法,目的是找到比n大的同时是2的次方幂的一个整数
workQueues = new WorkQueue[n];
ns = STARTED;
}
}
finally
{
//初始化完成后取消锁定并且更新初始化标识
unlockRunState(rs, (rs & ~RSLOCK) | ns);
}
}
//经过上面的赋值,r是随机数,m是数组长度-1也就是对应的mask,SQMASK是共享WQ的长度范围
//如果在对应的位置存在工作队列,则进入工作队列的竞争流程
else if ((q = ws[k = r & m & SQMASK]) != null)
{
//竞争workqueue锁成功
if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1))
{
ForkJoinTask<?>[] a = q.array;
int s = q.top;
boolean submitted = false; // initial submission or resizing
try
{
//如果task数组不为空且未满
//或者task数组扩容成功
if ((a != null && a.length > s + 1 - q.base) || (a = q.growArray()) != null)
{
//计算得到task在数组要放入的偏移量
int j = (((a.length - 1) & s) << ASHIFT) + ABASE;
//只放入storestore屏障,这是为了性能考虑。
U.putOrderedObject(a, j, task);
U.putOrderedInt(q, QTOP, s + 1);
submitted = true;
}
}
finally
{
U.compareAndSwapInt(q, QLOCK, 1, 0);
}
if (submitted)
{
signalWork(ws, q);
return;
}
}
move = true; // move on failure
}
//如果队列不存在,并且整个Pool的锁尚未被持有。则尝试初始化一个工作队列
else if (((rs = runState) & RSLOCK) == 0)
{ // create new queue
//创建了一个用于共享的Workqueue
q = new WorkQueue(this, null);
q.hint = r;
//k是上面流程发现的在workqueues中为null的slot下标,workQueue内的config意味着当前的workQueue的下标是工作模式。是独占,还是共享等。
q.config = k | SHARED_QUEUE;
q.scanState = INACTIVE;
rs = lockRunState(); // publish index
//rs大于0意味着线程池么有停止,剩余的条件均是判断对应的slot位置仍然是null
if (rs > 0 && (ws = workQueues) != null && k < ws.length && ws[k] == null)
ws[k] = q; // else terminated
unlockRunState(rs, rs & ~RSLOCK);
}
else
move = true; // move if busy
//这个写法看起来容易和上面混在一起。其实已经是一个新的if开头了。如果move为true,就意味着需要切换更新线程的随机值了
if (move)
r = ThreadLocalRandom.advanceProbe(r);
}
}
尝试唤醒处于等待堆栈栈顶的工作线程来执行任务。如果没有空闲线程且整体线程数不足,则增加工作线程。
final void signalWork(WorkQueue[] ws, WorkQueue q) {
long c; int sp, i; WorkQueue v; Thread p;
//ctl小于0就是AC部分小于0,意味着没有足够的激活中的执行资源
while ((c = ctl) < 0L) { // too few active
//低32位为0,意味着当前没有正在等待执行的线程
if ((sp = (int)c) == 0) { // no idle workers
//(c & ADD_WORKER)!=0 推断出TC小于0,意味着整体执行资源不足。
if ((c & ADD_WORKER) != 0L) // too few workers
tryAddWorker(c);
break;
}
if (ws == null) // unstarted/terminated
break;
//如果wq数组的长度小于等待线程持有的wq的下标,意味着pool已经终止了
if (ws.length <= (i = sp & SMASK)) // terminated
break;
//如果等待线程持有的wq的下标在Pool的WQ数组中已经为空,意味着Pool开始执行终止流程了。
if ((v = ws[i]) == null) // terminating
break;
//生成等待线程的下一个scanState的值。增加SS_SEQ的值为是为了保证每一次scanState都在变化,用于版本控制。避免CAS中的ABA问题。
int vs = (sp + SS_SEQ) & ~INACTIVE; // next scanState
//d==0,意味着到这一步,之前的处于等待的worker的状态没有变化
int d = sp - v.scanState; // screen CAS
//只有先成功更新ctl才能更新自身的scanState,每个地方都遵循这个顺序
//增加AC的数值,同时将SP部分恢复到上一个等待线程的数据
long nc = (UC_MASK & (c + AC_UNIT)) | (SP_MASK & v.stackPred);
if (d == 0 && U.compareAndSwapLong(this, CTL, c, nc)) {
v.scanState = vs; // activate v
//如果该worker线程处于休眠状态,唤醒。
if ((p = v.parker) != null)
U.unpark(p);
break;
}
//任务是放在q这个WQ里面的。如果q还有任务,意味着还可以继续唤醒等待线程,因为存在可以偷取的任务。否则的话,可能没有任务可以偷取了,直接退出循环
if (q != null && q.base == q.top) // no more work
break;
}
}
获得运行状态的锁。
private int lockRunState()
{
int rs;
return (
(
//如果当前运行状态的锁被其他线程得到
((rs = runState) & RSLOCK) != 0
//或者运行状态没有锁但是竞争锁失败
|| !U.compareAndSwapInt(this, RUNSTATE, rs, rs |= RSLOCK)//
) ?
//等待直到获取锁
awaitRunStateLock()
//之前的步骤成功得到锁,直接返回结果
: rs
);
}
尝试竞争运行锁,直到成功
private int awaitRunStateLock()
{
Object lock;
boolean wasInterrupted = false;
for (int spins = SPINS, r = 0, rs, ns;;)
{
//在运行锁没有被其他线程得到的情况尝试cas竞争锁
if (((rs = runState) & RSLOCK) == 0)
{
if (U.compareAndSwapInt(this, RUNSTATE, rs, ns = rs | RSLOCK))
{
if (wasInterrupted)
{
try
{
Thread.currentThread().interrupt();
}
catch (SecurityException ignore)
{
}
}
return ns;
}
}
//将r初始化为随机数种子
else if (r == 0)
r = ThreadLocalRandom.nextSecondarySeed();
//如果spin大于0对r进行随机数演算。
else if (spins > 0)
{
r ^= r << 6;
r ^= r >>> 21;
r ^= r << 7; // xorshift
//根据随机数结果对spin进行递减操作
if (r >= 0)
--spins;
}
//如果在上面的步骤都完成的情况下,并且forkjoinpool还没有初始化意味着较高的竞争,主动让出cpu
else if ((rs & STARTED) == 0 || (lock = stealCounter) == null)
Thread.yield(); // initialization race
//如果走到这里意味着线程发现线程池已经初始化了,但是本线程竞争运行锁失败,此时在运行字段上cas放入需要通知的标识。
else if (U.compareAndSwapInt(this, RUNSTATE, rs, rs | RSIGNAL))
{
//如果成功,就以stealCounter为对象锁执行等待。
synchronized (lock)
{
//如果通知标识存在,则线程阻塞等待其他线程完成工作
if ((runState & RSIGNAL) != 0)
{
try
{
lock.wait();
}
catch (InterruptedException ie)
{
if (!(Thread.currentThread() instanceof ForkJoinWorkerThread))
wasInterrupted = true;
}
}
//否则唤醒所有在这个对象锁上执行等待的线程
else
lock.notifyAll();
}
}
}
}
解锁运行锁。如果发现通知标识,则复位该标识并且进行线程唤醒
private void unlockRunState(int oldRunState, int newRunState)
{
//如果cas失败意味着在该cas之前或者同时,运行锁被设置了通知标识
if (!U.compareAndSwapInt(this, RUNSTATE, oldRunState, newRunState))
{
Object lock = stealCounter;
//直接清除运行锁上的通知标识
//这里不需要通过cas。因为当runState被更新后,其他线程想要放上通知标识是通过cas完成,而由于其他线程的预期值都是锁定的状态,与新值不符,都会失败。
//所以这里直接更新是ok的
runState = newRunState; // clears RSIGNAL bit
//更新完成之后,由于需要获得lock的sync锁,因此无论何种时序,都可以处于等待状态的线程恢复过来。
if (lock != null)
synchronized (lock)
{
lock.notifyAll();
}
}
}
不断尝试增加一个worker线程直到以下情况的发生
+ 当前Pool正在尝试终止
+ 增加成功
+ 当前激活worker数量超过配置的并发数并且没有处于等待的worker线程
private void tryAddWorker(long c) {
boolean add = false;
do {
//增加一个执行资源数。得到的计算结果就是nc。
long nc = ((AC_MASK & (c + AC_UNIT)) |
(TC_MASK & (c + TC_UNIT)));
if (ctl == c) {
int rs, stop; // check if terminating
if ((stop = (rs = lockRunState()) & STOP) == 0)
add = U.compareAndSwapLong(this, CTL, c, nc);
unlockRunState(rs, rs & ~RSLOCK);
if (stop != 0)
break;
//如果ctl更新成功,则确实的新增一个worker线程
if (add) {
//如果增加worker的意图成功,则进入创建环节。
createWorker();
break;
}
}
//如果激活线程数到达或者超过配置的并发数,并且当前不存在处于等待的worker线程。则退出循环。
} while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0);
}
创建一个worker线程。创建成功则返回true。创建失败则在pool中取消注册该worker,并且返回false
private boolean createWorker() {
ForkJoinWorkerThreadFactory fac = factory;
Throwable ex = null;
ForkJoinWorkerThread wt = null;
try {
if (fac != null && (wt = fac.newThread(this)) != null) {
wt.start();
return true;
}
} catch (Throwable rex) {
ex = rex;
}
deregisterWorker(wt, ex);
return false;
}
为新生成的ForkJoinWorkerThread创建一个私有的非共享的WorkQueue。并且将该WQ放入到Pool的WQ数组中。该WQ的模式即为Pool的工作模式。
final WorkQueue registerWorker(ForkJoinWorkerThread wt) {
UncaughtExceptionHandler handler;
wt.setDaemon(true); // configure thread
if ((handler = ueh) != null)
wt.setUncaughtExceptionHandler(handler);
WorkQueue w = new WorkQueue(this, wt);
int i = 0; // assign a pool index
int mode = config & MODE_MASK;
int rs = lockRunState();
try {
WorkQueue[] ws; int n; // skip if no array
if ((ws = workQueues) != null && (n = ws.length) > 0) {
//得到一个初始化的数值。该数值的含义在尽可能避免碰撞
int s = indexSeed += SEED_INCREMENT; // unlikely to collide
int m = n - 1;
//得到一个奇数下标
i = ((s << 1) | 1) & m; // odd-numbered indices
//如果发生了碰撞,则不断移动下标。下标的移动步长为数组长度的一半。
if (ws[i] != null) { // collision
int probes = 0;
//step是大于或等于WQ数组长度的一半的最小偶数。
int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2;
while (ws[i = (i + step) & m] != null) {
//不断尝试移动下标,如果接近2次完整的遍历都未曾发现空的槽位,则2倍扩容WQ数组
if (++probes >= n) {
workQueues = ws = Arrays.copyOf(ws, n <<= 1);
m = n - 1;
probes = 0;
}
}
}
//workQueue数组的大小受限于TC。也就是受限于并发数限制。并发数则限制在0x7fff内。
w.hint = s; // use as random seed
//当前workqueue的模式是workpool的模式。且非共享。
w.config = i | mode;
w.scanState = i; // publication fence
ws[i] = w;
}
} finally {
unlockRunState(rs, rs & ~RSLOCK);
}
wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1)));
return w;
}
一个ForkjoinWorkerThread的主要循环。扫描WQ数组,偷取任务进行执行(有可能偷取的任务就是自身的任务)。没有任务时则进行等待。
runWorker(WorkQueue w) {
//对WQ执行初始化和适当的扩容。
w.growArray(); // allocate queue
int seed = w.hint; // initially holds randomization hint
int r = (seed == 0) ? 1 : seed; // avoid 0 for xorShift
for (ForkJoinTask<?> t;;) {
if ((t = scan(w, r)) != null)
w.runTask(t);
else if (!awaitWork(w, r))
break;
r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
}
}
扫描WQ数组并且尝试偷取一个任务。扫描起始于一个随机位置r,不断向前递增。如果一轮扫描中没有发现任何可以偷取的偷取,则尝试将自身设置为非激活状态,并且ctl的ac值-1。 如果再次扫描一轮,仍然处于非激活状态并且整个WQ数组状态稳定。则退出扫描并且返回null。
而如果扫描时发现了可以偷取的任务,自身处于激活状态则尝试偷取,否则尝试激活一个worker(可能是自己也可能是别人)。
private ForkJoinTask<?> scan(WorkQueue w, int r) {
WorkQueue[] ws; int m;
if ((ws = workQueues) != null && (m = ws.length - 1) > 0 && w != null) {
int ss = w.scanState; // initially non-negative
//计算初始随机位置origin
for (int origin = r & m, k = origin, oldSum = 0, checkSum = 0;;) {
WorkQueue q; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
int b, n; long c;
//从Pool的WQ数组中挑选一个随机槽位上的WQ。该WQ不为空
if ((q = ws[k]) != null) {
//挑选的WQ对象,存在着可以偷取的任务(top-base大于0时意味着存在任务)
if ((n = (b = q.base) - q.top) < 0 &&
(a = q.array) != null) { // non-empty
long i = (((a.length - 1) & b) << ASHIFT) + ABASE;
//如果发现一个可以偷取的任务
if ((t = ((ForkJoinTask<?>)
U.getObjectVolatile(a, i))) != null &&
q.base == b) {
//读取到该WQ队列头部的task并且此时该队列的base尚未变化
//如果当前worker处于激活状态则尝试偷取
if (ss >= 0) {
//将要偷取的task所在槽位cas方式置空。成功后则增加该WQ的base值并且返回偷取的任务。
if (U.compareAndSwapObject(a, i, t, null)) {
q.base = b + 1;
//n<-1,意味着当前WQ内的待提取任务超过1个。因此可以尝试唤醒该worker线程
if (n < -1)
signalWork(ws, q);
return t;
}
}
//这个条件意味着本次扫描是当前worker设置为非激活状态成功后的第一轮扫描。此时发现了可以偷取的任务,则尝试激活一个worker(可以是自己或者是别人)
else if (oldSum == 0 && // try to activate
w.scanState < 0)
tryRelease(c = ctl, ws[m & (int)c], AC_UNIT);
}
//如果当前是非激活状态,则尝试刷新。有可能上面的操作中激活的是自身
if (ss < 0) // refresh
ss = w.scanState;
//如果走到这里意味着发现了可以偷取的任务,但是没有偷取到。因此移动到一个新的随机初始值。并重新开始整个扫描流程
r ^= r << 1; r ^= r >>> 3; r ^= r << 10;
origin = k = r & m; // move and rescan
oldSum = checkSum = 0;
continue;
}
//选中的WQ没有可以偷取任务时增加checkSum
checkSum += b;
}
//让k+=1.如果循环完一个数组长度,则尝试执行一些操作
if ((k = (k + 1) & m) == origin) {
//ss>=0成立。意味着当前worker处于激活状态。
//ss == (ss = w.scanState)意味着一轮扫描结束,worker的状态没有发生改变并且处于非激活状态
//oldSum == (oldSum = checkSum) 意味着一轮扫描结束,整个WQ数组的内容没有发生改变
//后两个条件同时为真,意味着连续的两轮扫描中,整个WQ数组状态稳定。
if ((ss >= 0 || (ss == (ss = w.scanState))) &&
oldSum == (oldSum = checkSum)) {
//如果已经是非激活状态了,则直接退出
if (ss < 0 || w.qlock < 0) // already inactive
break;
//将状态设置为负数,也就是非激活状态。
int ns = ss | INACTIVE; // try to inactivate
//设定新的ctl值。首先是AC部分减去1.然后是SP部分更新为当前worker的内容。
long nc = ((SP_MASK & ns) |
(UC_MASK & ((c = ctl) - AC_UNIT)));
//当前的worker保留了上一个留存于SP部分的worker信息。
w.stackPred = (int)c; // hold prev stack top
//非volatile写的方式更新了scanState的值。因为下面还有cas操作,这里这样的更新操作可以节省性能。
U.putInt(w, QSCANSTATE, ns);
//如果cas方式更新ctl成功,则将ss设置为更新后的状态值,否则将scanState回退到更新前的状态值也就是ss的值。
if (U.compareAndSwapLong(this, CTL, c, nc))
ss = ns;
else
w.scanState = ss; // back out
}
checkSum = 0;
}
}
}
return null;
}
进入该方法的WQ,本身已经是非激活状态,并且将自身的scanState更新到了ctl中。
如果当前worker不是最后一个等待worker,则进入休眠状态等待被其他线程唤醒。
如果当前worker是最后一个worker,则区分不同情况处理。
以下几种情况该方法返回false表达该worker需要终止
/**
* 返回false意味着该worker线程需要终止了。也就是需要执行deregisterWorker方法
*/
private boolean awaitWork(WorkQueue w, int r) {
if (w == null || w.qlock < 0) // w is terminating
return false;
for (int pred = w.stackPred, spins = SPINS, ss;;) {
//能够进入该方法的worker都是处于非激活状态。如果发现再次被激活,则需要退出循环。
if ((ss = w.scanState) >= 0)
break;
else if (spins > 0) {
//类xorshift运算,得到下一个随机数
r ^= r << 6; r ^= r >>> 21; r ^= r << 7;
if (r >= 0 && --spins == 0) { // randomize spins
WorkQueue v; WorkQueue[] ws; int s, j; AtomicLong sc;
//检查worker堆栈中的上一个worker是否已经进入休眠状态。如果未曾进入休眠状态的话,意味着该worker也有可能不进入休眠。因此这里会通过设置spins的值继续进行自旋。
if (pred != 0 && (ws = workQueues) != null &&
(j = pred & SMASK) < ws.length &&
(v = ws[j]) != null && // see if pred parking
(v.parker == null || v.scanState >= 0))
spins = SPINS; // continue spinning
}
}
//worker线程被终止,则直接返回
else if (w.qlock < 0) // recheck after spins
return false;
else if (!Thread.interrupted()) {
long c, prevctl, parkTime, deadline;
int ac = (int)((c = ctl) >> AC_SHIFT) + (config & SMASK);
//计算结果ac的值含义是当前激活的worker数量
if ((ac <= 0 && tryTerminate(false, false)) ||
(runState & STOP) != 0) // pool terminating
return false;
//如果总的资源数已经超过了并发需求并且该worker是最后一个等待worker,则尝试终止该worker。如果通过ctl替换的方式无法终止,则通过超时的方式进行终止
if (ac <= 0 && ss == (int)c) { // is last waiter
//计算得到前一个ctl的值
prevctl = (UC_MASK & (c + AC_UNIT)) | (SP_MASK & pred);
//得到tc部分的值
int t = (short)(c >>> TC_SHIFT); // shrink excess spares
//如果总资源数超过并发数+2,则意味着worker数量太多,终止本worker。
//如果ctl更新成功,则直接返回false
if (t > 2 && U.compareAndSwapLong(this, CTL, c, prevctl))
return false;
//如果ctl更新失败则休眠一段时间后再次尝试
parkTime = IDLE_TIMEOUT * ((t >= 0) ? 1 : 1 - t);
deadline = System.nanoTime() + parkTime - TIMEOUT_SLOP;
}
else
prevctl = parkTime = deadline = 0L;
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this); // emulate LockSupport
w.parker = wt;
if (w.scanState < 0 && ctl == c) // recheck before park
U.park(false, parkTime);
U.putOrderedObject(w, QPARKER, null);
U.putObject(wt, PARKBLOCKER, null);
//被其他线程唤醒了
if (w.scanState >= 0)
break;
//休眠时间到达,并且ctl更新成功,则返回false。需要停止该worker
if (parkTime != 0L && ctl == c &&
deadline - System.nanoTime() <= 0L &&
U.compareAndSwapLong(this, CTL, c, prevctl))
return false; // shrink pool
}
}
return true;
}
等待给定的任务直到该任务完成。在等待的过程中,等待的worker并非直接进入阻塞状态。而是采取几个策略推进任务的整体执行
final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline)
{
int s = 0;
if (task != null && w != null)
{
ForkJoinTask<?> prevJoin = w.currentJoin;
U.putOrderedObject(w, QCURRENTJOIN, task);
CountedCompleter<?> cc = (task instanceof CountedCompleter) ? (CountedCompleter<?>) task : null;
for (;;)
{
if ((s = task.status) < 0)
break;
if (cc != null)
helpComplete(w, cc, 0);
//如果没有本地任务,或者无法执行给定任务。则尝试将偷取了给定任务的worker中的本地任务偷取来自己执行。
else if (w.base == w.top || w.tryRemoveAndExec(task))
helpStealer(w, task);
if ((s = task.status) < 0)
break;
long ms, ns;
if (deadline == 0L)
ms = 0L;
//如果最后期限已过,则直接返回
else if ((ns = deadline - System.nanoTime()) <= 0L)
break;
//等待时间最少是1ms。
else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
ms = 1L;
//如果补偿成功,则本worker阻塞一段时间。
if (tryCompensate(w))
{
task.internalWait(ms);
U.getAndAddLong(this, CTL, AC_UNIT);
}
}
U.putOrderedObject(w, QCURRENTJOIN, prevJoin);
}
return s;
}
只有当worker w没有本地任务的时候才会执行这个方法。
worker v 尝试从偷取了task的work stealer的本地任务中偷取一个任务来执行。
private void helpStealer(WorkQueue w, ForkJoinTask<?> task) {
WorkQueue[] ws = workQueues;
int oldSum = 0, checkSum, m;
if (ws != null && (m = ws.length - 1) >= 0 && w != null &&
task != null) {
do { // restart point
checkSum = 0; // for stability check
ForkJoinTask<?> subtask;
WorkQueue j = w, v; // v is subtask stealer
descent: for (subtask = task; subtask.status >= 0; ) {
//使用随机数初始化一个奇数值。然后遍历WQ数组。只遍历其中的worker部分也就是奇数部分。
for (int h = j.hint | 1, k = 0, i; ; k += 2) {
//没有可以偷取任务的worker,退出整个大的循环
if (k > m)
break descent;
if ((v = ws[i = (h + k) & m]) != null) {
//发现了一个worker v,该worker偷取的任务就是给定的任务task。
if (v.currentSteal == subtask) {
j.hint = i;
break;
}
checkSum += v.base;
}
}
for (;;) {
ForkJoinTask<?>[] a; int b;
checkSum += (b = v.base);
ForkJoinTask<?> next = v.currentJoin;
//1. 如果给定的任务已经完成
//2. 如果当前的worker v没有在等待给定任务
//3. 如果偷取给定任务的worker又偷取了别的任务
//意味着之前的数据已经过期,放弃
if (subtask.status < 0 || j.currentJoin != subtask ||
v.currentSteal != subtask) // stale
break descent;
//如果偷取任务的worker没有本地任务
if (b - v.top >= 0 || (a = v.array) == null) {
//偷取任务的worker没有在join的任务要完成
if ((subtask = next) == null)
break descent;
j = v;
break;
}
int i = (((a.length - 1) & b) << ASHIFT) + ABASE;
ForkJoinTask<?> t = ((ForkJoinTask<?>)
U.getObjectVolatile(a, i));
if (v.base == b) {
if (t == null) // stale
break descent;
//从偷取给定任务的worker处偷取了一个任务来执行
if (U.compareAndSwapObject(a, i, t, null)) {
v.base = b + 1;
ForkJoinTask<?> ps = w.currentSteal;
int top = w.top;
do {
U.putOrderedObject(w, QCURRENTSTEAL, t);
t.doExec();
//如果本worker偷取的任务执行的过程中,分裂了。那么继续获取分裂后的本地任务执行,直到本地任务都被完成
} while (task.status >= 0 &&
w.top != top &&
(t = w.pop()) != null);
U.putOrderedObject(w, QCURRENTSTEAL, ps);
//不相等意味着本地任务在分裂的时候,被其他的线程也偷取了一部分
if (w.base != w.top)
return; // can't further help
}
}
}
}
//循环两次,整个Pool的状态都是稳定的,没有新增任务。
} while (task.status >= 0 && oldSum != (oldSum = checkSum));
}
}
final int helpComplete(WorkQueue w, CountedCompleter<?> task,
int maxTasks) {
WorkQueue[] ws; int s = 0, m;
if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 &&
task != null && w != null) {
int mode = w.config; // for popCC
int r = w.hint ^ w.top; // arbitrary seed for origin
int origin = r & m; // first queue to scan
int h = 1; // 1:ran, >1:contended, <0:hash
for (int k = origin, oldSum = 0, checkSum = 0;;) {
CountedCompleter<?> p; WorkQueue q;
if ((s = task.status) < 0)
break;
if (h == 1 && (p = w.popCC(task, mode)) != null) {
p.doExec(); // run local task
if (maxTasks != 0 && --maxTasks == 0)
break;
origin = k; // reset
oldSum = checkSum = 0;
}
else { // poll other queues
if ((q = ws[k]) == null)
h = 0;
else if ((h = q.pollAndExecCC(task)) < 0)
checkSum += h;
if (h > 0) {
if (h == 1 && maxTasks != 0 && --maxTasks == 0)
break;
r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
origin = k = r & m; // move and restart
oldSum = checkSum = 0;
}
else if ((k = (k + 1) & m) == origin) {
if (oldSum == (oldSum = checkSum))
break;
checkSum = 0;
}
}
}
}
return s;
}
有意向阻塞worker v一段时间。因此这里尝试做出某种补偿策略。返回true意味着本worker可以阻塞
private boolean tryCompensate(WorkQueue w)
{
boolean canBlock;
WorkQueue[] ws;
long c;
int m, pc, sp;
if (w == null || w.qlock < 0 || // caller terminating
(ws = workQueues) == null || (m = ws.length - 1) <= 0 || (pc = config & SMASK) == 0)
canBlock = false;
//如果存在休眠的worker则尝试唤醒。如果尝试唤醒成功,则本worker可以阻塞。
//外部代码中,当前worker如果从休眠中恢复,会增加AC的值。而在这里,因为唤醒成功的情况下本worker会阻塞。所以这里就不增加AC的值了。一增一减就归零了。
else if ((sp = (int) (c = ctl)) != 0)
canBlock = tryRelease(c, ws[sp & m], 0L);
//没有休眠中的worker
else
{
int ac = (int) (c >> AC_SHIFT) + pc;
int tc = (short) (c >> TC_SHIFT) + pc;
int nbusy = 0; // validate saturation
//检查所有的奇数位置,也就是检查所有的worker的状态。
//如果worker处于扫描任务的状态,标记为nbusy。遍历数组直到发现一个处于工作状态的线程
//如果都没有过于工作状态的worker,那么遍历结束时nbusy应该是总资源数的2倍。(2倍是因为其选择奇数的算法造成)
for (int i = 0; i <= m; ++i)
{
WorkQueue v;
if ((v = ws[((i << 1) | 1) & m]) != null)
{
if ((v.scanState & SCANNING) != 0)
break;
++nbusy;
}
}
//有worker在处理任务或者ctl发生了变化。
if (nbusy != (tc << 1) || ctl != c)
canBlock = false; // unstable or stale
//如果总资源大于配置的并发,激活worker数量大于1,本worker也没有任务
//则尝试在不唤醒休眠线程的情况下,单纯让自身陷入等待状态。
//所以这里让AC-1
else if (tc >= pc && ac > 1 && w.isEmpty())
{
long nc = ((AC_MASK & (c - AC_UNIT)) | (~AC_MASK & c)); // uncompensated
canBlock = U.compareAndSwapLong(this, CTL, c, nc);
}
//如果总worker数量超过了最大的限定worker数量,抛出异常
else if (tc >= MAX_CAP || (this == common && tc >= pc + commonMaxSpares))
throw new RejectedExecutionException("Thread limit exceeded replacing blocked worker");
//尝试增加一个worker线程。这里只是增加了TC部分的值。
//AC部分的值在外部方法中增加
else
{ // similar to tryAddWorker
boolean add = false;
int rs; // CAS within lock
long nc = ((AC_MASK & c) | (TC_MASK & (c + TC_UNIT)));
if (((rs = lockRunState()) & STOP) == 0)
add = U.compareAndSwapLong(this, CTL, c, nc);
unlockRunState(rs, rs & ~RSLOCK);
canBlock = add && createWorker(); // throws on exception
}
}
return canBlock;
}
在Pool中取消该WQ的注册。主要内容是
worker会退出有两种情况。
final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) {
WorkQueue w = null;
//将当前的workqueue从WQ数组中删除
if (wt != null && (w = wt.workQueue) != null) {
WorkQueue[] ws; // remove index from array
int idx = w.config & SMASK;
int rs = lockRunState();
if ((ws = workQueues) != null && ws.length > idx && ws[idx] == w)
ws[idx] = null;
unlockRunState(rs, rs & ~RSLOCK);
}
//更新ctl。删除一个资源数。主要就是在AC和TC部分-1
long c;
do {} while (!U.compareAndSwapLong
(this, CTL, c = ctl, ((AC_MASK & (c - AC_UNIT)) |
(TC_MASK & (c - TC_UNIT)) |
(SP_MASK & c))));
if (w != null) {
//设置qlock为-1,表明该worker已经终止。
w.qlock = -1;
w.transferStealCount(this);
w.cancelAll(); // cancel remaining tasks
}
//本worker线程退出,因此确认下是否需要唤醒休眠线程,或者是在资源不足的情况下增加一个worker线程。
for (;;) { // possibly replace
WorkQueue[] ws; int m, sp;
//如果当前pool已经处于终止过程中,说明不需要新增worker资源,退出。
if (tryTerminate(false, false) || w == null || w.array == null ||
(runState & STOP) != 0 || (ws = workQueues) == null ||
(m = ws.length - 1) < 0)
break;
//如果存在处于休眠等待的worker线程,则直接唤醒
if ((sp = (int)(c = ctl)) != 0) {
if (tryRelease(c, ws[sp & m], AC_UNIT))
break;
}
//如果是发生了异常导致了worker线程的终止。并且当前激活的worker资源少于预定的并发数,则尝试增加一个worker线程用于弥补本worker线程退出造成的影响。
else if (ex != null && (c & ADD_WORKER) != 0L) {
tryAddWorker(c);
break;
}
else
break;
}
if (ex == null) // help clean on way out
ForkJoinTask.helpExpungeStaleExceptions();
else // rethrow
ForkJoinTask.rethrow(ex);
}
尝试执行Pool的终止流程。大致流程如下
/**
* enable为true,意味着开启Pool的SHUTDOWN流程。
* now为true,意味着立刻进入STOP流程,否则就需要Pool当中不存在激活的worker以及未执行的任务时才能进入STOP阶段
* 返回true,意味着整个池子已经终止或者正在终止中
*/
private boolean tryTerminate(boolean now, boolean enable) {
int rs;
if (this == common) // cannot shut down
return false;
if ((rs = runState) >= 0) {
if (!enable)
return false;
rs = lockRunState(); // enter SHUTDOWN phase
unlockRunState(rs, (rs & ~RSLOCK) | SHUTDOWN);
}
//尚未进入STOP阶段的话,则尝试进入
if ((rs & STOP) == 0) {
if (!now) { // check quiescence
for (long oldSum = 0L;;) { // repeat until stable
WorkQueue[] ws; WorkQueue w; int m, b; long c;
long checkSum = ctl;
//(int)(checkSum >> AC_SHIFT) + (config & SMASK)就是当前的激活的worker数量
if ((int)(checkSum >> AC_SHIFT) + (config & SMASK) > 0)
return false; // still active workers
if ((ws = workQueues) == null || (m = ws.length - 1) <= 0)
break; // check queues
for (int i = 0; i <= m; ++i) {
if ((w = ws[i]) != null) {
//发现worker仍然有任务可以执行,则尝试唤醒worker线程w
if ((b = w.base) != w.top || w.scanState >= 0 ||
w.currentSteal != null) {
tryRelease(c = ctl, ws[m & (int)c], AC_UNIT);
return false; // arrange for recheck
}
checkSum += b;
//首先关闭共享的workqueue
if ((i & 1) == 0)
w.qlock = -1; // try to disable external
}
}
//两次循环checkSum未变化,意味着Pool已经稳定,退出循环
if (oldSum == (oldSum = checkSum))
break;
}
}
//STOP阶段完成
if ((runState & STOP) == 0) {
rs = lockRunState();
unlockRunState(rs, (rs & ~RSLOCK) | STOP);
}
}
int pass = 0; // 3 passes to help terminate
for (long oldSum = 0L;;) { // or until done or stable
WorkQueue[] ws; WorkQueue w; ForkJoinWorkerThread wt; int m;
long checkSum = ctl;
//如果总资源数小于等于0,或者workQueues已经为空,意味着Pool已经完成TERMINATED阶段的工作。将runState设定为TERMINATED状态
if ((short)(checkSum >>> TC_SHIFT) + (config & SMASK) <= 0 ||
(ws = workQueues) == null || (m = ws.length - 1) <= 0) {
if ((runState & TERMINATED) == 0) {
rs = lockRunState(); // done
//设定当前Pool为TERMINATED状态
unlockRunState(rs, (rs & ~RSLOCK) | TERMINATED);
synchronized (this) { notifyAll(); } // for awaitTermination
}
break;
}
for (int i = 0; i <= m; ++i) {
if ((w = ws[i]) != null) {
checkSum += w.base;
//设置qlock,这样其他的worker线程会发现,并且尝试自我终止
w.qlock = -1;
//非首轮扫描,则首先清除队列中的剩余任务。然后终止该worker线程
if (pass > 0) {
w.cancelAll(); // clear queue
if (pass > 1 && (wt = w.owner) != null) {
//中断该worker线程
if (!wt.isInterrupted()) {
try { // unblock join
wt.interrupt();
} catch (Throwable ignore) {
}
}
//如果worker线程处于非激活状态,则唤醒该线程。
//这里需要考虑下,因为如果worker线程准备进入休眠时上面的if发生了,那么worker线程仍然是会进入休眠的。所以这里需要再次执行唤醒。
//如果worker线程在上面的if之前就已经是休眠状态,则中断操作会立刻唤醒该worker线程
if (w.scanState < 0)
U.unpark(wt); // wake up
}
}
}
}
if (checkSum != oldSum) { // unstable
oldSum = checkSum;
pass = 0;
}
//终止流程走了太多次,放弃。
else if (pass > 3 && pass > m) // can't further help
break;
//至少扫描3次,并且Pool进入了稳定状态,则尝试释放所有的休眠等待worker线程
else if (++pass > 1) { // try to dequeue
long c; int j = 0, sp; // bound attempts
while (j++ <= m && (sp = (int)(c = ctl)) != 0)
tryRelease(c, ws[sp & m], AC_UNIT);
}
}
return true;
}
如果worker线程v是处于栈顶的等待线程,则增加ctl中的AC的值。如果增加成功,则唤醒worker线程v。
返回true意味着成功唤醒了一个worker线程。
/**
* c 当前的ctl值
* v 尝试唤醒的worker
* inc 需要增加的ac的值。
*/
private boolean tryRelease(long c, WorkQueue v, long inc) {
int sp = (int)c, vs = (sp + SS_SEQ) & ~INACTIVE; Thread p;
//确定v确实是在等待线程栈的栈顶才能尝试唤醒
if (v != null && v.scanState == sp) { // v is at top of stack
//计算唤醒之后的ctl的值,nc(next ctl)
long nc = (UC_MASK & (c + inc)) | (SP_MASK & v.stackPred);
if (U.compareAndSwapLong(this, CTL, c, nc)) {
v.scanState = vs;
if ((p = v.parker) != null)
U.unpark(p);
return true;
}
}
return false;
}
取消当前正在等待的join任务,取消当前偷取的任务,将任务队列中的任务逐一获取并且取消
final void cancelAll() {
ForkJoinTask<?> t;
if ((t = currentJoin) != null) {
currentJoin = null;
ForkJoinTask.cancelIgnoringExceptions(t);
}
if ((t = currentSteal) != null) {
currentSteal = null;
ForkJoinTask.cancelIgnoringExceptions(t);
}
while ((t = poll()) != null)
ForkJoinTask.cancelIgnoringExceptions(t);
}
WQ可以执行的操作有push,pop,和pull(就是其他线程的steal)。push和pop都是只能由本线程来完成,而poll则有可能是其他线程执行的。
workqueue内的task数组扩容
final ForkJoinTask<?>[] growArray()
{
ForkJoinTask<?>[] oldA = array;
int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY;
if (size > MAXIMUM_QUEUE_CAPACITY)
throw new RejectedExecutionException("Queue capacity exceeded");
int oldMask, t, b;
ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size];
//如果不是初始化并且数组内有数据,就要尝试迁移
if (oldA != null && (oldMask = oldA.length - 1) >= 0 && (t = top) - (b = base) > 0)
{
int mask = size - 1;
do
{
//迁移不是简单通过拷贝完成。而是需要cas竞争,将之前数组的内容移动到新的数组中
ForkJoinTask<?> x;
int oldj = ((b & oldMask) << ASHIFT) + ABASE;
int j = ((b & mask) << ASHIFT) + ABASE;
x = (ForkJoinTask<?>) U.getObjectVolatile(oldA, oldj);
if (x != null && U.compareAndSwapObject(oldA, oldj, x, null))
U.putObjectVolatile(a, j, x);
} while (++b != t);
}
return a;
}
final void push(ForkJoinTask<?> task)
{
ForkJoinTask<?>[] a;
ForkJoinPool p;
int b = base, s = top, n;
if ((a = array) != null)
{ // ignore if queue removed
int m = a.length - 1; // fenced write for task visibility
U.putOrderedObject(a, ((m & s) << ASHIFT) + ABASE, task);
U.putOrderedInt(this, QTOP, s + 1);
//如果n<=1,意味着该worker很可能拿走处理完自身的任务之后会大概率进入休眠。因此这里已经推送了一个任务进来可以尝试下唤醒等待堆栈栈顶的等待worker。
if ((n = s - b) <= 1)
{
if ((p = pool) != null)
p.signalWork(p.workQueues, this);
}
else if (n >= m)
growArray();
}
}
将给定的任务设置为currentSteal
的值,并且执行。
执行完毕后执行本地任务。
final void runTask(ForkJoinTask<?> task) {
if (task != null) {
//设置扫描状态为未扫描。也就是将最低位bit设置为0.因为初始状态下scanState必然是奇数,因此设置为偶数时就意味着处于任务执行中。
scanState &= ~SCANNING;
//执行偷取来的任务
(currentSteal = task).doExec();
//执行完毕设置为null用于帮助gc。这里没有使用直接赋值主要是提升写效率。
U.putOrderedObject(this, QCURRENTSTEAL, null);
//执行本地任务
execLocalTasks();
ForkJoinWorkerThread thread = owner;
//如果当前偷取的任务数已经超过了int的上限,则将该值加入到Pool的偷取总数中。
if (++nsteals < 0) // collect on overflow
transferStealCount(pool);
//任务执行完毕,恢复scanState到扫描任务的数值
scanState |= SCANNING;
if (thread != null)
thread.afterTopLevelExec();
}
}
final void execLocalTasks()
{
int b = base, m, s;
ForkJoinTask<?>[] a = array;
// s=top-1是实际存在task的槽位下标。这三个条件说明本地任务数组中存在任务
if (b - (s = top - 1) <= 0 && a != null && (m = a.length - 1) >= 0)
{
// 如果不是先进先出,那就是后进先出也就是栈模式。则从s位置不断取出任务直到b位置。
if ((config & FIFO_QUEUE) == 0)
{
for (ForkJoinTask<?> t;;)
{
// 先尝试获取任务,获取任务成功。才能真正的减少top。因为其他的线程可能是从base处往top处偷取任务。并且是先偷取任务,后移动base。所以可能造成base值未增加,但是base处的任务已经被拿走了。
if ((t = (ForkJoinTask<?>) U.getAndSetObject(a, ((m & s) << ASHIFT) + ABASE, null)) == null)
break;
// 取出任务并且设置top减少1.
U.putOrderedInt(this, QTOP, s);
t.doExec();
// 表达式成立,意味着base==top。说明本地任务已经清空
if (base - (s = top - 1) > 0)
break;
}
}
// 如果先进先出,则执行下面的逻辑
else
pollAndExecAll();
}
}
不断的尝试从base槽位取得任务直到任务数组为空
final void pollAndExecAll()
{
for (ForkJoinTask<?> t; (t = poll()) != null;)
t.doExec();
}
从WQ中的数组的base槽位通过cas竞争方式取得一个任务。重复该流程直到取得任务或者任务数组为空
final ForkJoinTask<?> poll()
{
ForkJoinTask<?>[] a;
int b;
ForkJoinTask<?> t;
//本地WQ的任务数组存在可以执行的任务
//每一次循环都需要重新获取base的值。因为其他线程可能更新了该值
while ((b = base) - top < 0 && (a = array) != null)
{
int j = (((a.length - 1) & b) << ASHIFT) + ABASE;
t = (ForkJoinTask<?>) U.getObjectVolatile(a, j);
//获取数据的过程中base没有发生变化。因为其他线程也会从base处偷取任务,所以这里先判断一次
if (base == b)
{
if (t != null)
{
//通过cas方式将b下标处设置为null。如果设置成功,意味着获取数据成功,设置成功后才能递增base
if (U.compareAndSwapObject(a, j, t, null))
{
base = b + 1;
return t;
}
}
//t为null意味着b槽位被其他线程获取,因此base递增的动作留给其他线程完成。本处检测当前槽位b是否已经是数组中最后一个有任务的槽位。
else if (b + 1 == top) // now empty
break;
}
}
return null;
}
将本worker偷取的任务数总量增加到Pool的统计数字中
final void transferStealCount(ForkJoinPool p) {
AtomicLong sc;
if (p != null && (sc = p.stealCounter) != null) {
int s = nsteals;
nsteals = 0; // if negative, correct for overflow
sc.getAndAdd((long)(s < 0 ? Integer.MAX_VALUE : s));
}
}
取消当前的所有任务
final void cancelAll() {
ForkJoinTask<?> t;
if ((t = currentJoin) != null) {
currentJoin = null;
ForkJoinTask.cancelIgnoringExceptions(t);
}
if ((t = currentSteal) != null) {
currentSteal = null;
ForkJoinTask.cancelIgnoringExceptions(t);
}
while ((t = poll()) != null)
ForkJoinTask.cancelIgnoringExceptions(t);
}
如果给定的任务处于当前wq的top位置,则cas方式尝试取出。如果取出成功返回true。取出失败或者给定任务不是在top位置,返回false
final boolean tryUnpush(ForkJoinTask<?> t)
{
ForkJoinTask<?>[] a;
int s;
if ((a = array) != null && (s = top) != base && U.compareAndSwapObject(a, (((a.length - 1) & --s) << ASHIFT) + ABASE, t, null))
{
U.putOrderedInt(this, QTOP, s);
return true;
}
return false;
}
遍历本地任务,如果给定任务是本地任务,则尝试从本地任务堆栈中取出该任务(如果是栈顶任务直接取出,如果是中间任务则尝试用空任务替换),并且执行该任务。
如果没有本地任务并且无法确定给定任务的状态,返回true
final boolean tryRemoveAndExec(ForkJoinTask<?> task) {
ForkJoinTask<?>[] a; int m, s, b, n;
if ((a = array) != null && (m = a.length - 1) >= 0 &&
task != null) {
while ((n = (s = top) - (b = base)) > 0) {
//遍历top到base位置的本地任务
for (ForkJoinTask<?> t;;) { // traverse from s to b
long j = ((--s & m) << ASHIFT) + ABASE;
//如果获取的任务为空,意味着遍历已经结束
if ((t = (ForkJoinTask<?>)U.getObject(a, j)) == null)
//s+1==top意味着没有本地任务了。
return s + 1 == top; // shorter than expected
//给定任务是本地任务中的一个
else if (t == task) {
boolean removed = false;
//如果给定任务是栈顶任务,则尝试获取
if (s + 1 == top) { // pop
if (U.compareAndSwapObject(a, j, task, null)) {
U.putOrderedInt(this, QTOP, s);
removed = true;
}
}
//如果不是栈顶任务,那就是中间的任务。本地任务的执行要么是从base端开始,要么是从top端开始,不能从中间开始。因此这里尝试使用一个空任务替换掉这个任务本身。然后才能尝试执行该任务。
//如果base尚未变化才能执行下面的流程。在base变化的情况下,就需要重新开始执行整个流程
else if (base == b) // replace with proxy
removed = U.compareAndSwapObject(
a, j, task, new EmptyTask());
if (removed)
task.doExec();
break;
}
//如果栈顶任务已经不是等待处理状态,尝试抛弃。
else if (t.status < 0 && s + 1 == top) {
if (U.compareAndSwapObject(a, j, t, null))
U.putOrderedInt(this, QTOP, s);
break; // was cancelled
}
//遍历完成
//遍历完成意味着
//1.本地任务不为空
//2.给定任务不是本地任务
if (--n == 0)
return false;
}
if (task.status < 0)
return false;
}
}
return true;
}
生成一个ForkJoinWorkThread。并且创建一个私有的WQ。该WQ是在Pool的WQ数组中。
protected ForkJoinWorkerThread(ForkJoinPool pool) {
// Use a placeholder until a useful name can be set in registerWorker
super("aForkJoinWorkerThread");
this.pool = pool;
this.workQueue = pool.registerWorker(this);
}
启动worker线程,最重要的操作就是调用了pool.runWorker(workQueue);
public void run() {
if (workQueue.array == null) { // only run once
Throwable exception = null;
try {
onStart();
pool.runWorker(workQueue);
} catch (Throwable ex) {
exception = ex;
} finally {
try {
onTermination(exception);
} catch (Throwable ex) {
if (exception == null)
exception = ex;
} finally {
pool.deregisterWorker(this, exception);
}
}
}
}
尝试取消任务。所谓的取消任务,就是设置任务的状态属性为取消。
static final void cancelIgnoringExceptions(ForkJoinTask<?> t) {
if (t != null && t.status >= 0) {
try {
t.cancel(false);
} catch (Throwable ignore) {
}
}
}
设置任务的状态属性为取消
public boolean cancel(boolean mayInterruptIfRunning) {
return (setCompletion(CANCELLED) & DONE_MASK) == CANCELLED;
}
final int doExec() {
int s; boolean completed;
//status大于0意味着任务尚未取消,可以执行
if ((s = status) >= 0) {
try {
completed = exec();
} catch (Throwable rex) {
return setExceptionalCompletion(rex);
}
if (completed)
s = setCompletion(NORMAL);
}
return s;
}
将这个任务推送到当前worker的wq中。如果当前线程不是forkjoinworkerthread,则推送到统一的公共Pool中。
public final ForkJoinTask<V> fork() {
Thread t;
if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
((ForkJoinWorkerThread)t).workQueue.push(this);
else
ForkJoinPool.common.externalPush(this);
return this;
}
public final V join() {
int s;
if ((s = doJoin() & DONE_MASK) != NORMAL)
reportException(s);
return getRawResult();
}
//这段代码对三元表达式用的,不管怎么格式化,可读性都不是很高,只能勉强看下
private int doJoin()
{
int s;
Thread t;
ForkJoinWorkerThread wt;
ForkJoinPool.WorkQueue w;
return (s = status) < 0 ?
s :
//当前线程是forkjoinworkerthread
((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
//判断当前任务是否处于WQ的top位置。如果是的话并且成功取得该任务,则直接执行
(w = (wt = (ForkJoinWorkerThread) t).workQueue).tryUnpush(this) && (s = doExec()) < 0 ?
//否则就等待该任务执行完毕
s : wt.pool.awaitJoin(w, this, 0L)
:
//如果当前线程不是forkjointhreadpool
externalAwaitDone();
}
该方法是worker线程来调用。
设定任务的signal标志位为true。并且等待直到超时或者被其他线程唤醒。
final void internalWait(long timeout) {
int s;
if ((s = status) >= 0 && // force completer to issue notify
U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
synchronized (this) {
if (status >= 0)
try { wait(timeout); } catch (InterruptedException ie) { }
else
notifyAll();
}
}
}
设置任务状态为完成。如果有线程在等待该任务的完成,则唤醒所有等待的线程。
private int setCompletion(int completion) {
for (int s;;) {
if ((s = status) < 0)
return s;
if (U.compareAndSwapInt(this, STATUS, s, s | completion)) {
if ((s >>> 16) != 0)
synchronized (this) { notifyAll(); }
return completion;
}
}
}
ctl是一个long整型。以16bit为单位被分成4个区间。
如果ctl的低32位为0,意味着当前没有处于等待状态的worker线程。也就是没有空闲资源。
该数组长度为2的次方幂。该数组的槽位可能存在null值。数组具有如下特性
+ 奇数下标的槽位用于存储属于worker的私有workqueue
+ 偶数下标的槽位用于存储共享的workqueue。共享workqueue的槽位下标最大不超过64.
该字段用于表达worker线程的状态。是一个int类型的字段。包含如下信息
1<<16
的值将最低位设置为0时意味着该worker获取到了一个任务,处于执行任务的状态
因为这个值会用于判断该worker是否处于激活状态。因为每次scanState从非激活状态转为激活状态时除了将最高位设置为0也需要递增一个步长,用于避免更新判断出现ABA的问题。这个步长就是SS_SEQ
,也就是1<<16
。这个递进不会导致溢出。因为是先递进,然后设置最高位为0.
用于完成对worker的锁定工作。值具备如下含义
用于表达task当前的任务状态
volatile int status; // accessed directly by pool and workers
static final int DONE_MASK = 0xf0000000; // mask out non-completion bits
static final int NORMAL = 0xf0000000; // must be negative
static final int CANCELLED = 0xc0000000; // must be < NORMAL
static final int EXCEPTIONAL = 0x80000000; // must be < CANCELLED
static final int SIGNAL = 0x00010000; // must be >= 1 << 16
static final int SMASK = 0x0000ffff; // short bits for tags