目录
一、ForkJoinWorkerThread
1、定义
2、run / getPoolIndex
二、InnocuousForkJoinWorkerThread
三、ForkJoinWorkerThreadFactory
四、WorkQueue
1、定义
2、push / pop / poll / pollAt / peek / tryUnpush
3、runTask
4、tryRemoveAndExec
5、popCC / pollAndExecCC
五、ManagedBlocker
本篇博客重点讲解ForkJoinPool依赖的几个基础类。
ForkJoinWorkerThread继承自Thread,重点改写了其run方法实现,该类包含的实例属性如下:
//负责管理该线程的线程池实现
final ForkJoinPool pool; // the pool this thread works in
//保存待执行任务的任务队列
final ForkJoinPool.WorkQueue workQueue; // work-stealing mechanics
除此之外,还多个表示属性偏移量的静态属性,通过static代码块初始化,如下:
该类的构造方法如下:
protected ForkJoinWorkerThread(ForkJoinPool pool) {
//指定初始线程名,registerWorker方法中会修改线程名
super("aForkJoinWorkerThread");
this.pool = pool;
//将当前线程注册到Pool,注册完成后返回WorkQueue实例
this.workQueue = pool.registerWorker(this);
}
ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
AccessControlContext acc) {
//指定初始线程名和ThreadGroup,registerWorker方法中会修改线程名
super(threadGroup, null, "aForkJoinWorkerThread");
//修改属性inheritedAccessControlContext
U.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, acc);
//清空本地线程变量
eraseThreadLocals(); // clear before registering
this.pool = pool;
//将当前线程注册到Pool,注册完成后返回WorkQueue实例
this.workQueue = pool.registerWorker(this);
}
final void eraseThreadLocals() {
//将保存本地线程变量的两个Map置为null,即清空可能残留的本地线程变量
U.putObject(this, THREADLOCALS, null);
U.putObject(this, INHERITABLETHREADLOCALS, null);
}
第一种是给DefaultForkJoinWorkerThreadFactory创建新线程使用,第二种是给子类InnocuousForkJoinWorkerThread使用。
ThreadPoolExecutor中的Worker是实现了Runnable接口,将Worker实例传入Thread的构造方法中执行run方法的,ForkJoinWorkerThread是继承Thread,直接改写其run方法,其实现如下:
//返回当前线程在线程池中的编号
public int getPoolIndex() {
//注意workQueue是registerWorker后返回的,与线程是1对1的关系
return workQueue.getPoolIndex();
}
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);
}
}
}
}
protected void onStart() {
}
protected void onTermination(Throwable exception) {
}
InnocuousForkJoinWorkerThread是ForkJoinWorkerThread的一个内部类,继承自ForkJoinWorkerThread,表示一个特殊的无任何访问权限的线程,不属于任何用户定义的线程组,当执行afterTopLevelExec后会将原线程的本地变量都清空,该类的定义如下:
static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
/** 创建一个全局的线程组 */
private static final ThreadGroup innocuousThreadGroup =
createThreadGroup();
/** An AccessControlContext supporting no privileges */
private static final AccessControlContext INNOCUOUS_ACC =
new AccessControlContext(
new ProtectionDomain[] {
//无任务访问权限
new ProtectionDomain(null, null)
});
InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
//此构造方法会清空本地线程变量
super(pool, innocuousThreadGroup, INNOCUOUS_ACC);
}
@Override // to erase ThreadLocals
void afterTopLevelExec() {
//清空本地线程变量
eraseThreadLocals();
}
@Override // to always report system loader
public ClassLoader getContextClassLoader() {
//默认是返回父线程的contextClassLoader,此处改写直接返回SystemClassLoader
return ClassLoader.getSystemClassLoader();
}
@Override //无法设置该线程的异常处理器,即默认为null,出现异常后线程自动退出
public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { }
@Override // 不支持设置ClassLoader,直接抛出异常
public void setContextClassLoader(ClassLoader cl) {
throw new SecurityException("setContextClassLoader");
}
//Java中ThreadGroup只提供关联线程的管理维护功能,跟底层的Linux线程组无关联
private static ThreadGroup createThreadGroup() {
try {
sun.misc.Unsafe u = sun.misc.Unsafe.getUnsafe();
Class> tk = Thread.class;
Class> gk = ThreadGroup.class;
long tg = u.objectFieldOffset(tk.getDeclaredField("group"));
long gp = u.objectFieldOffset(gk.getDeclaredField("parent"));
//获取当前线程的线程组
ThreadGroup group = (ThreadGroup)
u.getObject(Thread.currentThread(), tg);
while (group != null) {
//获取父线程组
ThreadGroup parent = (ThreadGroup)u.getObject(group, gp);
if (parent == null)
//找到了最初的祖先级的线程组,使用该线程组创建一个新的线程组
return new ThreadGroup(group,
"InnocuousForkJoinWorkerThreadGroup");
group = parent;
}
} catch (Exception e) {
throw new Error(e);
}
//正常不会进入此代码,直接抛出异常
throw new Error("Cannot create ThreadGroup");
}
}
ForkJoinWorkerThreadFactory是ForkJoinPool内部的一个public接口类,用于创建ForkJoinWorkerThread,该接口有两个对应的实现类DefaultForkJoinWorkerThreadFactory和InnocuousForkJoinWorkerThreadFactory,分别用于创建普通的ForkJoinWorkerThread和特殊的InnocuousForkJoinWorkerThread,其实现如下:
public static interface ForkJoinWorkerThreadFactory {
public ForkJoinWorkerThread newThread(ForkJoinPool pool);
}
static final class DefaultForkJoinWorkerThreadFactory
implements ForkJoinWorkerThreadFactory {
public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
return new ForkJoinWorkerThread(pool);
}
}
static final class InnocuousForkJoinWorkerThreadFactory
implements ForkJoinWorkerThreadFactory {
/**
* An ACC to restrict permissions for the factory itself.
* The constructed workers have no permissions set.
*/
private static final AccessControlContext innocuousAcc;
static {
Permissions innocuousPerms = new Permissions();
//对应的RuntimePermission为modifyThread
innocuousPerms.add(modifyThreadPermission);
//允许改写获取ContextClassLoader的方法
innocuousPerms.add(new RuntimePermission(
"enableContextClassLoaderOverride"));
//允许修改ThreadGroup
innocuousPerms.add(new RuntimePermission(
"modifyThreadGroup"));
innocuousAcc = new AccessControlContext(new ProtectionDomain[] {
new ProtectionDomain(null, innocuousPerms)
});
}
public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
return (ForkJoinWorkerThread.InnocuousForkJoinWorkerThread)
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public ForkJoinWorkerThread run() {
return new ForkJoinWorkerThread.
InnocuousForkJoinWorkerThread(pool);
}}, innocuousAcc);
}
}
WorkQueue是ForkJoinPool的内部类,用来保存待执行的任务的队列,该类没有实现队列接口,完全是ForkJoinPool定制的,其访问权限是包级访问权限。该类包含的实例属性如下:
//当前队列的状态,如果小于0表示未激活,大于0表示已激活
//如果最后一位是1,即是奇数,则表示关联的Worker线程正在扫描获取待执行的任务,最后一位是0,即偶数,表示关联的Worker线程正在执行任务
//scanState是会变化的,每次改变时是在当前ctl的基础上加上SS_SEQ
volatile int scanState; // versioned, <0: inactive; odd:scanning
//当前WorkQueue被标记成未激活状态时ctl属性的低32位的值,其中低16位保存在此之间被标记为未激活状态的WorkQueue在数组中的索引
int stackPred; // pool stack (ctl) predecessor
//表示当前队列从其他队列中偷过来并执行的任务数
int nsteals; // number of steals
//hint是在WorkerQueue创建时初始化的,初始值为当前线程的Probe
//当从其他WorkerQueue获取未执行的任务时,用来临时保存被偷取任务的WorkerQueue的索引
int hint; // randomization and stealer index hint
//高16位保存队列的类型,是先进先出还是后进先出,取决于线程池的配置,如果小于0表示该队列是共享的
//低16位保存当前队列在队列数组中的位置
int config; // pool index and mode
//1表示已加锁,负值表示当前队列已终止,不能接受新的任务,Worker退出或者线程池终止时会将qlock属性置为-1
//正常是0
volatile int qlock; // 1: locked, < 0: terminate; else 0
//下一次poll时对应的数组索引
volatile int base; // index of next slot for poll
//下一次push时对应的数组索引
int top; // index of next slot for push
//实际保存ForkJoinTask的数组
ForkJoinTask>[] array; // the elements (initially unallocated)
//关联的线程池
final ForkJoinPool pool; // the containing pool (may be null)
//拥有此队列的ForkJoinWorkerThread
final ForkJoinWorkerThread owner; // owning thread or null if shared
//如果队列长期为空则会被置为未激活状态,关联的Worker线程也会休眠,parker属性就是记录关联的Worker线程,跟上面的owner是一样的
volatile Thread parker; // == owner during call to park; else null
//必须等待currentJoin执行完成而让当前线程阻塞
volatile ForkJoinTask> currentJoin; // task being joined in awaitJoin
//当前线程通过scan方法获取待执行的任务,该任务可能是当前队列的,也可能是其他某个队列的
volatile ForkJoinTask> currentSteal; // mainly used by helpStealer
该类包含的静态属性通过static代码块初始化,表示某个属性的偏移量,如下:
除此之外,还有两个静态常量,如下:
//初始队列容量
static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
//最大队列容量
static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
该类的构造方法如下:
注意base和top的初始值都不是0,而是初始值的一半,即从数组的中间开始插入新元素或者移除元素。
//插入一个新任务
final void push(ForkJoinTask> task) {
ForkJoinTask>[] a; ForkJoinPool p;
int b = base, s = top, n;
//执行runWorker方法时会通过growArray方法初始化array
//一旦关联的ForkJoinWorkerThread解除注册了则会将其置为null
if ((a = array) != null) { //如果队列被移除了则忽略
int m = a.length - 1;
//将task保存到数组中,m & s的结果就是新元素在数组中的位置,如果s大于m则求且的结果是0,又从0逐步增长到索引最大值
U.putOrderedObject(a, ((m & s) << ASHIFT) + ABASE, task);
//修改top属性,加1,注意top属性会一直加1
U.putOrderedInt(this, QTOP, s + 1);
if ((n = s - b) <= 1) { //如果原来数组是空的
if ((p = pool) != null)
//唤醒因为待执行任务为空而阻塞的线程
p.signalWork(p.workQueues, this);
}
else if (n >= m) //说明数组满了
growArray();
}
}
//数组扩容,会将原老数组的元素复制到新数组中,老数组中对应的位置置为null
final ForkJoinTask>[] growArray() {
ForkJoinTask>[] oldA = array;
//获取扩容后的容量,如果array未初始化则是INITIAL_QUEUE_CAPACITY
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 { //从base往top遍历,将老数组中的元素拷贝到新数组中,老数组对应位置的数组元素置为null
ForkJoinTask> x;
int oldj = ((b & oldMask) << ASHIFT) + ABASE;
int j = ((b & mask) << ASHIFT) + ABASE;
//获取原数组oldj处的元素
x = (ForkJoinTask>)U.getObjectVolatile(oldA, oldj);
if (x != null &&
U.compareAndSwapObject(oldA, oldj, x, null))//将老数组oldj处的元素置为null,将x保存到新数组的j处
U.putObjectVolatile(a, j, x);
} while (++b != t);
}
return a;
}
//弹出上一次push的元素
final ForkJoinTask> pop() {
ForkJoinTask>[] a; ForkJoinTask> t; int m;
if ((a = array) != null && (m = a.length - 1) >= 0) {
for (int s; (s = top - 1) - base >= 0;) { //有未移除的元素
//获取上一次push的元素在数组中的索引
long j = ((m & s) << ASHIFT) + ABASE;
//如果该索引的元素为null,则终止循环
if ((t = (ForkJoinTask>)U.getObject(a, j)) == null)
break;
//将j处的元素置为null,修改top属性,返回j处的元素
if (U.compareAndSwapObject(a, j, t, null)) {
U.putOrderedInt(this, QTOP, s);
return t;
}
}
}
//数组未初始化或者数组为空
return null;
}
//获取并移除base对应的数组元素
final ForkJoinTask> poll() {
ForkJoinTask>[] a; int b; ForkJoinTask> t;
//数组不为空且还有未移除的元素
while ((b = base) - top < 0 && (a = array) != null) {
//获取base对应数组索引处的元素
int j = (((a.length - 1) & b) << ASHIFT) + ABASE;
t = (ForkJoinTask>)U.getObjectVolatile(a, j);
if (base == b) { //如果base未发生改变
if (t != null) {
//通过cas将其置为null,base加1,返回该元素
if (U.compareAndSwapObject(a, j, t, null)) {
base = b + 1;
return t;
}
}
else if (b + 1 == top) // now empty
break;
}//如果base发生改变则下一次while循环重新读取base
}
return null;
}
//获取指定数组索引的元素,要求b等于base,否则返回null
final ForkJoinTask> pollAt(int b) {
ForkJoinTask> t; ForkJoinTask>[] a;
if ((a = array) != null) {
int j = (((a.length - 1) & b) << ASHIFT) + ABASE;
if ((t = (ForkJoinTask>)U.getObjectVolatile(a, j)) != null &&
//只有base等于b的时候才会将对应的数组元素置为null并返回该元素
base == b && U.compareAndSwapObject(a, j, t, null)) {
base = b + 1;
return t;
}
}
return null;
}
final ForkJoinTask> peek() {
ForkJoinTask>[] a = array; int m;
//如果数组未初始化
if (a == null || (m = a.length - 1) < 0)
return null;
//如果是后进先出则是top - 1 ,如果是先进先出则是base
int i = (config & FIFO_QUEUE) == 0 ? top - 1 : base;
int j = ((i & m) << ASHIFT) + ABASE;
//获取队列头或者队列尾的元素,取决于队列的类型
return (ForkJoinTask>)U.getObjectVolatile(a, j);
}
//如果t是上一次push的元素,则将top减1,对应的数组元素置为null,返回true
final boolean tryUnpush(ForkJoinTask> t) {
ForkJoinTask>[] a; int s;
if ((a = array) != null && (s = top) != base &&
U.compareAndSwapObject
//如果t是上一次push插入的元素,则将其置为null,同时修改s
(a, (((a.length - 1) & --s) << ASHIFT) + ABASE, t, null)) {
U.putOrderedInt(this, QTOP, s);
return true;
}
return false;
}
runTask方法会执行指定的任务,并且将任务数组中包含的所有未处理任务都执行完成,注意指定的任务不一定是当前WorkQueue中包含的,有可能是从其他WorkQueue中偷过来的。
//执行特定任务,并执行完当前数组中包含的所有未处理任务
final void runTask(ForkJoinTask> task) {
if (task != null) {
//SCANNING的值就是1,将最后一位置为0,表示正在执行任务
scanState &= ~SCANNING; // mark as busy
//执行task
(currentSteal = task).doExec();
//将currentSteal属性置为null
U.putOrderedObject(this, QCURRENTSTEAL, null); // release for GC
//执行当前数组中包含的未处理的任务
execLocalTasks();
ForkJoinWorkerThread thread = owner;
if (++nsteals < 0)
//nsteals已经超过最大值了,变成负值了,则将其累加到ForkJoinPool的stealCounter属性中
//并重置为0
transferStealCount(pool);
//重新打标成SCANNING
scanState |= SCANNING;
if (thread != null)
//执行回调方法
thread.afterTopLevelExec();
}
}
final void execLocalTasks() {
int b = base, m, s;
ForkJoinTask>[] a = array;
//如果数组已经初始化且包含未处理的元素
if (b - (s = top - 1) <= 0 && a != null &&
(m = a.length - 1) >= 0) {
if ((config & FIFO_QUEUE) == 0) {
//如果是后进先出队列,从top开始往前遍历直到base
for (ForkJoinTask> t;;) {
//获取s对应的数组元素
if ((t = (ForkJoinTask>)U.getAndSetObject
(a, ((m & s) << ASHIFT) + ABASE, null)) == null)
break;
//修改top
U.putOrderedInt(this, QTOP, s);
t.doExec(); //执行任务
if (base - (s = top - 1) > 0) //所有元素都遍历完了
break;
}
}
else
//如果是先进先出
pollAndExecAll();
}
}
final void pollAndExecAll() {
for (ForkJoinTask> t; (t = poll()) != null;)
t.doExec();
}
final void transferStealCount(ForkJoinPool p) {
AtomicLong sc;
if (p != null && (sc = p.stealCounter) != null) {
int s = nsteals;
//恢复成0
nsteals = 0; // if negative, correct for overflow
//累加到ForkJoinPool的stealCounter属性中
sc.getAndAdd((long)(s < 0 ? Integer.MAX_VALUE : s));
}
}
//如果队列为空且不知道task的状态,则返回true
//如果找到目标task,会将其从数组中移除并执行
//在遍历数组的过程中,如果发现任务被取消了,则会将其从数组中丢弃
final boolean tryRemoveAndExec(ForkJoinTask> task) {
ForkJoinTask>[] a; int m, s, b, n;
if ((a = array) != null && (m = a.length - 1) >= 0 &&
task != null) { //数组和task非空
while ((n = (s = top) - (b = base)) > 0) { //还有未处理的任务
for (ForkJoinTask> t;;) { // traverse from s to b
//s先减1再求且
long j = ((--s & m) << ASHIFT) + ABASE;
//如果索引为j的数组元素为null
if ((t = (ForkJoinTask>)U.getObject(a, j)) == null)
return s + 1 == top; //如果为true,说明数组是空的
else if (t == task) {
//找到了匹配的任务
boolean removed = false;
if (s + 1 == top) { //目标task就是上一次push的元素
if (U.compareAndSwapObject(a, j, task, null)) {
//将对应的数组元素置为null,然后修改top属性
U.putOrderedInt(this, QTOP, s);
removed = true;
}
}
//s+1不等于top,即目标task位于中间的位置,将用一个空的EmptyTask代替
else if (base == b) // replace with proxy
removed = U.compareAndSwapObject(
a, j, task, new EmptyTask());
if (removed)
//如果成功移除该task,则执行该任务
task.doExec();
break; //终止内存for循环,通过外层的while循环,重启for循环
}
//t不等于task
//如果t被取消了,且t位于栈顶
else if (t.status < 0 && s + 1 == top) {
if (U.compareAndSwapObject(a, j, t, null))
U.putOrderedInt(this, QTOP, s); //修改top属性,即将被取消掉的任务给丢弃掉
break; // was cancelled
}
//先减n减1,再判断n是否为0,如果为0,说明数组中所有元素都遍历完了,返回false
if (--n == 0)
return false;
}//for循环结束
if (task.status < 0) //task被取消了,返回false
return false;
}//while循环结束
}
return true;
}
//如果栈顶的元素是CountedCompleter,则以该元素为起点向上遍历他的父节点,直到找到目标task元素,将栈顶的
//CountedCompleter从数组中移除并返回,top减1
final CountedCompleter> popCC(CountedCompleter> task, int mode) {
int s; ForkJoinTask>[] a; Object o;
if (base - (s = top) < 0 && (a = array) != null) {
//如果数组非空
long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE;
if ((o = U.getObjectVolatile(a, j)) != null &&
(o instanceof CountedCompleter)) {
//如果栈顶的任务是CountedCompleter
CountedCompleter> t = (CountedCompleter>)o;
for (CountedCompleter> r = t;;) {
if (r == task) {//如果找到目标task
if (mode < 0) { //该队列是共享的,会被多个线程修改,必须加锁
if (U.compareAndSwapInt(this, QLOCK, 0, 1)) { //加锁
if (top == s && array == a && //如果top属性和array属性都未改变,将索引为j的元素置为null
U.compareAndSwapObject(a, j, t, null)) {
U.putOrderedInt(this, QTOP, s - 1); //top减1
U.putOrderedInt(this, QLOCK, 0); //释放锁
return t;
}
//上述if不成立,解锁
U.compareAndSwapInt(this, QLOCK, 1, 0);
}
}
//mode大于等于0,是某个Worker线程独享的,不需要加锁
else if (U.compareAndSwapObject(a, j, t, null)) { //将索引为j的元素置为null
U.putOrderedInt(this, QTOP, s - 1);
return t;
}
break;
}
else if ((r = r.completer) == null) //遍历父节点,如果为null说明都遍历完了
break;
}
}
}
return null;
}
//如果base对应的数组元素是CountedCompleter,则以该节点作为起点,往上遍历其父节点,如果找到目标节点task,则执行并返回1
final int pollAndExecCC(CountedCompleter> task) {
int b, h; ForkJoinTask>[] a; Object o;
if ((b = base) - top >= 0 || (a = array) == null) //如果数组为空
h = b | Integer.MIN_VALUE; // to sense movement on re-poll
else {
//如果数组不为空,获取base对应的元素
long j = (((a.length - 1) & b) << ASHIFT) + ABASE;
if ((o = U.getObjectVolatile(a, j)) == null)//如果base对应的元素为null,返回2
h = 2; // retryable
else if (!(o instanceof CountedCompleter)) //如果base对应的元素不是CountedCompleter,返回-1
h = -1; // unmatchable
else {
//base对应的元素是CountedCompleter
CountedCompleter> t = (CountedCompleter>)o;
for (CountedCompleter> r = t;;) {
if (r == task) {
//匹配到目标元素
if (base == b &&
U.compareAndSwapObject(a, j, t, null)) {
//base未改变且成功将j对应的数组元素置为null,将base加1,并执行该任务,返回1
base = b + 1;
t.doExec();
h = 1; // success
}
else
//base变了或者cas失败,返回2
h = 2; // lost CAS
break;
}
else if ((r = r.completer) == null) { //往上遍历父节点,如果为null,则返回-1
h = -1; // unmatched
break;
}
}
}
}
return h;
}
ManagedBlocker接口的定义比较简单,如下:
其中block方法用于将当前线程阻塞,isReleasable方法返回true表示不需要阻塞了,该接口的典型实现就是Phaser的内部类QNode,可以参考《Java8 Phaser 源码解析》 。
ManagedBlocker接口通常跟ForkJoinPool的静态方法managedBlock配合使用,该方法的实现如下:
public static void managedBlock(ManagedBlocker blocker)
throws InterruptedException {
ForkJoinPool p;
ForkJoinWorkerThread wt;
Thread t = Thread.currentThread();
if ((t instanceof ForkJoinWorkerThread) && //如果是ForkJoinWorkerThread
(p = (wt = (ForkJoinWorkerThread)t).pool) != null) {
WorkQueue w = wt.workQueue;
while (!blocker.isReleasable()) { //如果需要阻塞
if (p.tryCompensate(w)) { //进一步判断是否需要阻塞
try {
//让当前线程阻塞
do {} while (!blocker.isReleasable() &&
!blocker.block());
} finally {
//活跃的线程数加1
U.getAndAddLong(p, CTL, AC_UNIT);
}
break;
}
}
}
else {
//普通的JavaThread
do {} while (!blocker.isReleasable() &&
!blocker.block());
}
}