目录
1、定义
2、构造方法
3、invoke / execute / submit / invokeAll
4、externalPush / tryExternalUnpush
5、lockRunState / unlockRunState
本篇博客重点讲解ForkJoinPool的定义及其提交任务到线程池的实现。
ForkJoinPool的类继承关系如下:
该类包含的属性如下:
//最高的16位表示获取线程数,第二个16位表示总的线程数
//如果有空闲线程,最低的16位中保存空闲线程关联的WorkQueue在WorkQueue数组中的索引
volatile long ctl; // main pool control
//描述线程池的状态
volatile int runState; // lockable status
//高16位保存线程池的队列模式,FIFO或者LIFO
//低16位保存线程池的parallelism属性
final int config; // parallelism, mode
//累加SEED_INCREMENT生成的一个随机数,决定新增的Worker对应的WorkQueue在数组中的索引
int indexSeed; // to generate worker index
//WorkQueue数组
volatile WorkQueue[] workQueues; // main registry
//生成Worker线程的工厂类
final ForkJoinWorkerThreadFactory factory;
//异常处理器
final UncaughtExceptionHandler ueh; // per-worker UEH
//生成的Worker线程的线程名前缀
final String workerNamePrefix; // to create worker name string
//累计的从其他WorkQueue中偷过来的待执行的任务
volatile AtomicLong stealCounter; // also used as sync monitor
包含的静态属性如下:
//创建ForkJoinWorkerThread的工厂类
public static final ForkJoinWorkerThreadFactory
defaultForkJoinWorkerThreadFactory;
//线程池关闭时检查当前线程是否有此权限
private static final RuntimePermission modifyThreadPermission;
//common线程池
static final ForkJoinPool common;
//common线程池的parallelism属性
static final int commonParallelism;
//限制最大的线程数,默认值为常量DEFAULT_COMMON_MAX_SPARES,256
private static int commonMaxSpares;
//生成poolId使用
private static int poolNumberSequence;
// Unsafe mechanics
private static final sun.misc.Unsafe U;
private static final int ABASE;
private static final int ASHIFT;
private static final long CTL;
private static final long RUNSTATE;
private static final long STEALCOUNTER;
private static final long PARKBLOCKER;
private static final long QTOP;
private static final long QLOCK;
private static final long QSCANSTATE;
private static final long QPARKER;
private static final long QCURRENTSTEAL;
private static final long QCURRENTJOIN;
static {
//获取属性的偏移量
try {
U = sun.misc.Unsafe.getUnsafe();
Class> k = ForkJoinPool.class;
CTL = U.objectFieldOffset
(k.getDeclaredField("ctl"));
RUNSTATE = U.objectFieldOffset
(k.getDeclaredField("runState"));
STEALCOUNTER = U.objectFieldOffset
(k.getDeclaredField("stealCounter"));
Class> tk = Thread.class;
PARKBLOCKER = U.objectFieldOffset
(tk.getDeclaredField("parkBlocker"));
Class> wk = WorkQueue.class;
QTOP = U.objectFieldOffset
(wk.getDeclaredField("top"));
QLOCK = U.objectFieldOffset
(wk.getDeclaredField("qlock"));
QSCANSTATE = U.objectFieldOffset
(wk.getDeclaredField("scanState"));
QPARKER = U.objectFieldOffset
(wk.getDeclaredField("parker"));
QCURRENTSTEAL = U.objectFieldOffset
(wk.getDeclaredField("currentSteal"));
QCURRENTJOIN = U.objectFieldOffset
(wk.getDeclaredField("currentJoin"));
Class> ak = ForkJoinTask[].class;
//用于获取ForkJoinTask数组指定索引元素的偏移量
ABASE = U.arrayBaseOffset(ak);
int scale = U.arrayIndexScale(ak);
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
} catch (Exception e) {
throw new Error(e);
}
//DEFAULT_COMMON_MAX_SPARES的值是256
commonMaxSpares = DEFAULT_COMMON_MAX_SPARES;
defaultForkJoinWorkerThreadFactory =
new DefaultForkJoinWorkerThreadFactory();
modifyThreadPermission = new RuntimePermission("modifyThread");
common = java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction() {
public ForkJoinPool run() { return makeCommonPool(); }});
//获取common线程池的parallelism属性
int par = common.config & SMASK; // report 1 even if threads disabled
commonParallelism = par > 0 ? par : 1;
}
//创建common线程池
private static ForkJoinPool makeCommonPool() {
int parallelism = -1;
ForkJoinWorkerThreadFactory factory = null;
UncaughtExceptionHandler handler = null;
try { //读取三个属性值
String pp = System.getProperty
("java.util.concurrent.ForkJoinPool.common.parallelism");
String fp = System.getProperty
("java.util.concurrent.ForkJoinPool.common.threadFactory");
String hp = System.getProperty
("java.util.concurrent.ForkJoinPool.common.exceptionHandler");
//根据属性配置初始化变量
if (pp != null)
parallelism = Integer.parseInt(pp);
if (fp != null)
factory = ((ForkJoinWorkerThreadFactory)ClassLoader.
getSystemClassLoader().loadClass(fp).newInstance());
if (hp != null)
handler = ((UncaughtExceptionHandler)ClassLoader.
getSystemClassLoader().loadClass(hp).newInstance());
} catch (Exception ignore) {
}
if (factory == null) {
if (System.getSecurityManager() == null)
factory = defaultForkJoinWorkerThreadFactory;
else // use security-managed default
factory = new InnocuousForkJoinWorkerThreadFactory();
}
if (parallelism < 0 && //如果没有设置属性parallelism,则默认使用CPU核数减1,如果是单核的则为1
(parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
parallelism = 1;
if (parallelism > MAX_CAP) //如果配置的parallelism大于MAX_CAP,则为MAX_CAP,0x7fff,32767
parallelism = MAX_CAP;
//注意common线程池的模式是LIFO,后进先出
return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
"ForkJoinPool.commonPool-worker-");
}
包含的静态常量如下:
//用于获取保存在config属性低16位中的parallelism属性
static final int SMASK = 0xffff; // short bits == max index
//parallelism属性的最大值
static final int MAX_CAP = 0x7fff; // max #workers - 1
//跟SMASK相比,最后一位是0而不是1,用来计算遍历workQueues的步长
static final int EVENMASK = 0xfffe; // even short bits
//取值是126,二进制表示是1111110,WorkQueue数组元素个数的最大值
static final int SQMASK = 0x007e; // max 64 (even) slots
//WorkQueue.scanState属性中表示状态的位
//最低位为1表示关联的Worker线程正在扫描获取待执行的任务,为0表示正在执行任务
static final int SCANNING = 1; // false when running tasks
//最高位为1表示当前WorkQueue为非激活状态,刚创建时状态就是INACTIVE,可通过signalWork方法将其变成激活状态
//最高位为0表示当前WorkQueue为激活状态
static final int INACTIVE = 1 << 31; // must be negative
//一个自增值,ctl属性的低32位加上SS_SEQ,计算一个新的scanState
static final int SS_SEQ = 1 << 16; // version count
// ForkJoinPool.config 和 WorkQueue.config 属性中,高16位表示队列的模式
static final int MODE_MASK = 0xffff << 16; // top half of int
static final int LIFO_QUEUE = 0; //后进先出模式
static final int FIFO_QUEUE = 1 << 16; //先进先出模式
static final int SHARED_QUEUE = 1 << 31; //共享模式
//Worker线程的空闲时间,单位是纳秒
private static final long IDLE_TIMEOUT = 2000L * 1000L * 1000L; // 2sec
//允许的阻塞时间误差
private static final long TIMEOUT_SLOP = 20L * 1000L * 1000L; // 20ms
//commonMaxSpares的初始值,线程池中线程数的最大值
private static final int DEFAULT_COMMON_MAX_SPARES = 256;
//自旋等待的次数,设置成0可减少对CPU的占用,且没有对应的方法可以修改SPINS属性
private static final int SPINS = 0;
//生成随机数的种子
private static final int SEED_INCREMENT = 0x9e3779b9;
//获取低32位的值
private static final long SP_MASK = 0xffffffffL;
//获取高32位的值
private static final long UC_MASK = ~SP_MASK;
//活跃线程数,保存在ctl中的最高16位
private static final int AC_SHIFT = 48;
private static final long AC_UNIT = 0x0001L << AC_SHIFT;
private static final long AC_MASK = 0xffffL << AC_SHIFT;
//总的线程数,保存在ctl中的第二个16位
private static final int TC_SHIFT = 32;
private static final long TC_UNIT = 0x0001L << TC_SHIFT;
private static final long TC_MASK = 0xffffL << TC_SHIFT;
//如果第48位为1,表示需要新增一个Worker线程
//第48位对应于TC的最高位,如果为1,说明总的线程数小于parallelism属性,可以新增线程
private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign
//runState属性不同的位表示的含义,描述线程池的状态
//如果runState小于0,即最高位为1,说明线程池正在关闭的过程中
//如果runState大于0,说明线程池是正常运行的
private static final int RSLOCK = 1; //表示已加锁
private static final int RSIGNAL = 1 << 1; //表示有线程等待获取锁
private static final int STARTED = 1 << 2; //表示线程已启动
//表示线程池的状态是STOP,不接受新的任务且会丢弃掉任务队列中未执行的任务
private static final int STOP = 1 << 29;
//表示线程池已终止
private static final int TERMINATED = 1 << 30;
//表示线程池的状态是SHUTDOWN,不接受新的任务
private static final int SHUTDOWN = 1 << 31;
public ForkJoinPool() {
this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
defaultForkJoinWorkerThreadFactory, null, false);
}
public ForkJoinPool(int parallelism) {
this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
}
public ForkJoinPool(int parallelism,
ForkJoinWorkerThreadFactory factory,
UncaughtExceptionHandler handler,
boolean asyncMode) {
this(checkParallelism(parallelism),
checkFactory(factory),
handler,
asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
"ForkJoinPool-" + nextPoolId() + "-worker-");
checkPermission();
}
private static void checkPermission() {
SecurityManager security = System.getSecurityManager();
if (security != null)
security.checkPermission(modifyThreadPermission);
}
private static int checkParallelism(int parallelism) {
if (parallelism <= 0 || parallelism > MAX_CAP)
throw new IllegalArgumentException();
return parallelism;
}
private static ForkJoinWorkerThreadFactory checkFactory
(ForkJoinWorkerThreadFactory factory) {
if (factory == null)
throw new NullPointerException();
return factory;
}
private static final synchronized int nextPoolId() {
return ++poolNumberSequence;
}
private ForkJoinPool(int parallelism,
ForkJoinWorkerThreadFactory factory,
UncaughtExceptionHandler handler,
int mode,
String workerNamePrefix) {
this.workerNamePrefix = workerNamePrefix;
this.factory = factory;
this.ueh = handler;
//parallelism不能超过MAX_CAP,跟SMASK求且的结果不变
this.config = (parallelism & SMASK) | mode;
long np = (long)(-parallelism); // offset ctl counts
//左移48位后取高16位 和 左移32位后取第二个16位
//以parallelism是3为例,此时ctl是1111111111111101111111111111110100000000000000000000000000000000
this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
}
invoke方法是ForkJoinPool的特有方法,会将指定任务提交到任务队列中并阻塞当前线程等待任务执行完成;execute,submit,invokeAll方法都是改写了父类AbstractExecutorService的实现,原实现是将Runnable或者Callable接口包装成FutureTask,这里统一包装成ForkJoinTask的某个子类。
public T invoke(ForkJoinTask task) {
if (task == null)
throw new NullPointerException();
//将新任务加入到任务队列中
externalPush(task);
return task.join(); //等待任务执行完成
}
public void execute(ForkJoinTask> task) {
if (task == null)
throw new NullPointerException();
//将新任务加入到任务队列中
externalPush(task);
}
public void execute(Runnable task) {
if (task == null)
throw new NullPointerException();
ForkJoinTask> job;
if (task instanceof ForkJoinTask>) // avoid re-wrap
job = (ForkJoinTask>) task;
else
//如果不是ForkJoinTask,则进行一层保证
job = new ForkJoinTask.RunnableExecuteAction(task);
//将新任务加入到任务队列中
externalPush(job);
}
public ForkJoinTask submit(ForkJoinTask task) {
if (task == null)
throw new NullPointerException();
//将新任务加入到任务队列中
externalPush(task);
return task;
}
public ForkJoinTask submit(Callable task) {
//将Callable进行包装
ForkJoinTask job = new ForkJoinTask.AdaptedCallable(task);
//将新任务加入到任务队列中
externalPush(job);
return job;
}
public ForkJoinTask submit(Runnable task, T result) {
//将Runnable给包装成ForkJoinTask
ForkJoinTask job = new ForkJoinTask.AdaptedRunnable(task, result);
externalPush(job);
return job;
}
public ForkJoinTask> submit(Runnable task) {
if (task == null)
throw new NullPointerException();
ForkJoinTask> job;
if (task instanceof ForkJoinTask>) // avoid re-wrap
job = (ForkJoinTask>) task;
else
//将Runnable给包装成ForkJoinTask
job = new ForkJoinTask.AdaptedRunnableAction(task);
externalPush(job);
return job;
}
public List> invokeAll(Collection extends Callable> tasks) {
ArrayList> futures = new ArrayList<>(tasks.size());
boolean done = false;
try {
for (Callable t : tasks) {
//Callable包装成ForkJoinTask
ForkJoinTask f = new ForkJoinTask.AdaptedCallable(t);
futures.add(f);
externalPush(f);
}
for (int i = 0, size = futures.size(); i < size; i++)
((ForkJoinTask>)futures.get(i)).quietlyJoin(); //等待任务执行完成
done = true;
return futures;
} finally {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(false); //出现异常取消掉剩余的未执行任务
}
}
ForkJoinPool跟ThreadPoolExecutor不同,后者只有一个支持阻塞的任务队列,前者是有多个任务队列,任务队列的数量是大于2*parallelism的最小的2的整数次幂的值,且任务队列是非阻塞的,多个任务队列的设计跟LongAdder的设计思想类似,可减少高并发提交任务时减少对同一个队列的竞争,减少因加锁解锁等同步操作的性能损耗。
将某个任务提交到任务队列时,是根据m & r & SQMASK的方式来计算所属的任务队列,其中m等于任务队列数组的长度减1,r等于当前线程的probe属性,SQMASK是任务队列数组的最大个数。如果所属的任务队列未初始化,则会创建一个新的任务队列,注意新创建的任务队列是SHARED_QUEUE共享模式,即不属于某个Worker线程,且是INACTIVE状态的。
如果某个task是位于关联的任务队列的顶端,即是最近一次插入的task,则将其从任务队列中移除,如果成功移除则tryExternalUnpush返回true,否则返回false。
externalPush方法是invoke / execute / submit / invokeAll等方法的核心实现,将某个任务提交到任务队列中,如果当前线程的probe属性未初始化,则初始化probe属性;如果线程池未初始化则初始化线程池,初始化线程池就是根据parallelism属性初始化WorkQueue数组和stealCounter属性;如果该task关联的WorkQueue未初始化,则创建一个新的WorkQueue,新WorkQueue是SHARED_QUEUE和INACTIVE的,最后将任务添加到这个新的WorkQueue中;如果关联的WorkQueue不为空,则将其添加到关联的WorkQueue中。只要添加到WorkQueue成功,如果没有空闲的Worker线程且当前线程数小于parallelism属性则尝试创建一个新的Worker线程,否则尝试唤醒一个空闲的Worker线程。
另外从其tryAddWorker方法的实现可知,ForkJoinPool下线程池的最大线程数就是parallelism,不可能大于parallelism,可参考ADD_WORKER的调用链,如下:
有一种情形除外,某个ForkJoinTask通过awaitJoin方法阻塞了当前Worker线程的执行,如果当前WorkQueue中还有其他未执行的任务,则会创建新的Worker线程,导致总的线程数超过了parallelism,可参考实际创建Worker线程的creatWorker方法的调用链路,如下:
这几个方法的实现如下:
//如果task是上一次插入的且将其从队列成功移除,则返回true,否则返回false
final boolean tryExternalUnpush(ForkJoinTask> task) {
WorkQueue[] ws; WorkQueue w; ForkJoinTask>[] a; int m, s;
int r = ThreadLocalRandom.getProbe();
if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 && //线程池已初始化
(w = ws[m & r & SQMASK]) != null && //关联的WorkQueue非空
(a = w.array) != null && (s = w.top) != w.base) { // 关联的WorkQueue包含有未执行的任务
//j是上一次插入到数组中的索引
long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE;
if (U.compareAndSwapInt(w, QLOCK, 0, 1)) { //队列加锁
if (w.top == s && w.array == a && //top和array属性未变更
U.getObject(a, j) == task && //如果上一次插入到数组中的任务就是task
U.compareAndSwapObject(a, j, task, null)) { //成功将其修改为null
U.putOrderedInt(w, QTOP, s - 1); //top属性减1
U.putOrderedInt(w, QLOCK, 0); //队列解锁
return true;
}
U.compareAndSwapInt(w, QLOCK, 1, 0);//队列解锁
}
}
return false;
}
final void externalPush(ForkJoinTask> task) {
WorkQueue[] ws; WorkQueue q; int m;
int r = ThreadLocalRandom.getProbe();
int rs = runState; //runState的初始值为0
if ((ws = workQueues) != null && (m = (ws.length - 1)) >= 0 && //如果workQueues非空,该属性默认为null,说明线程池已初始化
(q = ws[m & r & SQMASK]) != null && //计算存放任务的WorkQueue,如果对应的WorkQueue非空
r != 0 && rs > 0 && //r不等于0说明当前线程的probe属性已初始化,rs大于0说明线程池已初始化且是正常运行的
U.compareAndSwapInt(q, QLOCK, 0, 1)) { //对WorkQueue加锁
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); //top属性加1
U.putIntVolatile(q, QLOCK, 0); //解锁
if (n <= 1)
//原任务队列是空的,此时新增了一个任务,则尝试新增Worker或者唤醒空闲的Worker
signalWork(ws, q);
return;
}
//WorkQueue解锁
U.compareAndSwapInt(q, QLOCK, 1, 0);
}
//初始化调用线程的Probe,线程池和关联的WorkQueue
//如果已初始化,则将任务保存到WorkQueue中
externalSubmit(task);
}
private void externalSubmit(ForkJoinTask> task) {
int r; // initialize caller's probe
if ((r = ThreadLocalRandom.getProbe()) == 0) { //初始化调用线程的Probe
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();
}
else if ((rs & STARTED) == 0 || //如果线程池还未启动,未初始化
((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()); //初始化stealCounter属性
//获取并行度,计算对应的数组长度
int p = config & SMASK; // ensure at least 2 slots
int n = (p > 1) ? p - 1 : 1;
//p是3,即4核,n为2时,计算的结果是8
//p是7,即8核,n为6时,计算的结果是16,算出来的n是大于2n的最小的2的整数次幂的值
n |= n >>> 1; n |= n >>> 2; n |= n >>> 4;
n |= n >>> 8; n |= n >>> 16; n = (n + 1) << 1;
//初始化workQueues
workQueues = new WorkQueue[n];
ns = STARTED;
}
} finally {
//将线程池标记为已启动
unlockRunState(rs, (rs & ~RSLOCK) | ns);
}
}
//线程池已启动
else if ((q = ws[k = r & m & SQMASK]) != null) {
//关联的WorkQueue不为null
if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) { //将WorkQueue加锁
ForkJoinTask>[] a = q.array;
int s = q.top;
boolean submitted = false; // initial submission or resizing
try { // locked version of push
if ((a != null && a.length > s + 1 - q.base) || //如果任务数组有剩余空间
(a = q.growArray()) != null) { //如果任务数组中没有剩余空间,则扩容
//计算任务数组中保存的位置并保存
int j = (((a.length - 1) & s) << ASHIFT) + ABASE;
U.putOrderedObject(a, j, task);
U.putOrderedInt(q, QTOP, s + 1);//top属性加1
submitted = true;
}
} finally {
//解锁
U.compareAndSwapInt(q, QLOCK, 1, 0);
}
if (submitted) { //如果任务已经提交到WorkQueue中
signalWork(ws, q); //新增Worker或者唤醒空闲的Worker
return;
}
}
//WorkQueue加锁失败
move = true; // move on failure
}
//关联的WorkQueue为null
else if (((rs = runState) & RSLOCK) == 0) { //线程池未加锁
q = new WorkQueue(this, null);
q.hint = r; //使用当前线程的probe初始化hint
q.config = k | SHARED_QUEUE; //模式是共享的,即不属于某个特定的Worker,k表示该WorkQueue在数组中的位置
q.scanState = INACTIVE;
rs = lockRunState(); //加锁
if (rs > 0 && (ws = workQueues) != null && //线程池已启动且workQueues非空
k < ws.length && ws[k] == null) //再次校验关联的WorkQueue为null
ws[k] = q; //将新的WorkQueue保存起来
unlockRunState(rs, rs & ~RSLOCK); //解锁,下一次for循环就将任务保存到该WorkQueue中
}
else
move = true; // move if busy
if (move) //如果WorkQueue加锁失败,则增加probe属性,下一次for循环则遍历下一个WorkQueue,即将该Task提交到其他的WorkQueue中
r = ThreadLocalRandom.advanceProbe(r);
}//for循环结束
}
//如果当前总的线程数小于parallelism,则signalWork会尝试创建新的Worker线程
//如果当前有空闲的Worker线程,则尝试唤醒一个,如果没有空闲的则直接返回
final void signalWork(WorkQueue[] ws, WorkQueue q) {
long c; int sp, i; WorkQueue v; Thread p;
while ((c = ctl) < 0L) { //ctl初始化时使用-parallelism,为负值表示活跃的线程数小于线程池初始化时设置的并行度要求
if ((sp = (int)c) == 0) { //取低32位的值,如果为0,则活跃线程数等于总的线程数,即没有空闲的线程数
if ((c & ADD_WORKER) != 0L) //不等于0,说明总的线程数小于parallelism属性,可以新增线程
tryAddWorker(c); //尝试创建新线程
//只要没有空闲的线程,此处就break,终止while循环
break;
}
//sp不等于0,即有空闲的线程,sp等于ctl的低32位
//ctl的最低16位保存最近空闲的Worker线程关联的WorkQueue在数组中的索引
if (ws == null) //线程池未初始化或者已终止
break;
if (ws.length <= (i = sp & SMASK)) //线程池已终止
break;
if ((v = ws[i]) == null) //线程池在终止的过程中
break;
//sp加SS_SEQ,非INACTIVE就是最高位0,再加31个1
//此处将空闲WorkQueue的INACTIVE表示去除,变成正常的激活状态
int vs = (sp + SS_SEQ) & ~INACTIVE; // next scanState
int d = sp - v.scanState; // screen CAS
//AC加1,UC_MASK取高32位的值,SP_MASK取低32位的值
//stackPred是v被标记成INACTIVE时ctl的低32位,可能保存着在v之前空闲的WorkQueue在数组中的索引
long nc = (UC_MASK & (c + AC_UNIT)) | (SP_MASK & v.stackPred);
if (d == 0 && U.compareAndSwapLong(this, CTL, c, nc)) {
//d等于0说明WorkQueue v关联的Worker是最近才空闲的
//修改ctl属性成功
v.scanState = vs; //将WorkQueue v标记成已激活
if ((p = v.parker) != null)
U.unpark(p); //唤醒等待的线程
break;
}
//如果d不等于0或者上述CAS修改失败,即已经有一个空闲Worker被其他线程给激活了
if (q != null && q.base == q.top) //任务队列为空,没有待执行的任务了,不需要激活空闲Worker或者创建新线程了
break;
//如果if不成立则继续下一次for循环
} //while循环结束
}
//尝试增加新线程
private void tryAddWorker(long c) {
boolean add = false;
do {
//AC和TC都加1
long nc = ((AC_MASK & (c + AC_UNIT)) |
(TC_MASK & (c + TC_UNIT)));
if (ctl == c) { //如果ctl未变更
int rs, stop; // check if terminating
if ((stop = (rs = lockRunState()) & STOP) == 0) //加锁成功且线程池未终止,则修改ctl
add = U.compareAndSwapLong(this, CTL, c, nc);
unlockRunState(rs, rs & ~RSLOCK); //解锁
if (stop != 0) //如果线程池已终止,则终止while循环
break;
if (add) {
//ctl修改成功,创建新的Worker
createWorker();
break;
}
}
//重新读取ctl,如果依然可以新增线程且空闲线程数为0,则继续下一次for循环新增Worker
} while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0);
}
//创建新的Worker,如果创建失败或者启动执行异常则通过deregisterWorker方法通知线程池将其解除注册
private boolean createWorker() {
ForkJoinWorkerThreadFactory fac = factory;
Throwable ex = null;
ForkJoinWorkerThread wt = null;
try {
if (fac != null && (wt = fac.newThread(this)) != null) {
wt.start(); //通过ThreadFactory创建一个新的Worker,并启动线程的执行
return true;
}
} catch (Throwable rex) {
ex = rex;
}
//创建的过程中有异常,通知线程池将其解除注册
deregisterWorker(wt, ex);
return false;
}
上述代码涉及ctl的位运算,可参考如下测试用例:
// Active counts
private static final int AC_SHIFT = 48;
private static final long AC_UNIT = 0x0001L << AC_SHIFT;
private static final long AC_MASK = 0xffffL << AC_SHIFT;
// Total counts
private static final int TC_SHIFT = 32;
private static final long TC_UNIT = 0x0001L << TC_SHIFT;
private static final long TC_MASK = 0xffffL << TC_SHIFT;
private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign
@Test
public void test16() throws Exception {
long np=-3l;
//初始状态
long ctl=((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
System.out.println(Long.toBinaryString(ctl));
System.out.println(ctl & ADD_WORKER);
System.out.println((short)(ctl >>> TC_SHIFT));
//新增一个线程
ctl = ((AC_MASK & (ctl + AC_UNIT)) |
(TC_MASK & (ctl + TC_UNIT)));
System.out.println(Long.toBinaryString(ctl));
System.out.println(ctl & ADD_WORKER);
System.out.println((short)(ctl >>> TC_SHIFT));
//新增一个线程
ctl = ((AC_MASK & (ctl + AC_UNIT)) |
(TC_MASK & (ctl + TC_UNIT)));
System.out.println(Long.toBinaryString(ctl));
System.out.println(ctl & ADD_WORKER);
System.out.println((short)(ctl >>> TC_SHIFT));
//新增一个线程
ctl = ((AC_MASK & (ctl + AC_UNIT)) |
(TC_MASK & (ctl + TC_UNIT)));
System.out.println(Long.toBinaryString(ctl));
System.out.println(ctl & ADD_WORKER); //新增了3个线程后等于0
System.out.println((short)(ctl >>> TC_SHIFT));
}
lockRunState将当前线程池加锁,如果当前runState已加锁或者CAS加锁失败则调用awaitRunStateLock等待锁释放并加锁;awaitRunStateLock方法会阻塞当前线程,直到锁释放被唤醒,然后尝试获取锁,如果获取失败则继续阻塞,直到获取成功为止;unlockRunState方法将当前线程池解锁,如果oldRunState跟当前的runstate属性不一致,说明有某个线程在等待获取锁,在runstate上加上了RSIGNAL标识,则直接修改runstate,去掉RSIGNAL标识,并唤醒所有等待获取锁的线程。
线程池加锁和解锁是成对出现的,用于线程池初始化或者终止,修改WorkerQueue数组,修改ctl属性时使用,参考lockRunState的调用链,如下:
其实现如下:
//执行加锁
private int lockRunState() {
int rs;
return ((((rs = runState) & RSLOCK) != 0 || //如果已经加锁
!U.compareAndSwapInt(this, RUNSTATE, rs, rs |= RSLOCK)) ? //如果未加锁则CAS加锁
//如果加锁失败调用awaitRunStateLock,阻塞当前线程等待获取锁,否则返回rs
awaitRunStateLock() : rs);
}
//执行解锁
private void unlockRunState(int oldRunState, int newRunState) {
if (!U.compareAndSwapInt(this, RUNSTATE, oldRunState, newRunState)) {
//如果cas修改失败,只能是oldRunState发生改变了,加上了RSIGNAL
//所以此处是直接重置runState,去除RSLOCK和RSIGNAL,并唤醒所有等待获取锁的线程
Object lock = stealCounter;
runState = newRunState; // clears RSIGNAL bit
if (lock != null)
//唤醒所有等待获取锁的线程
synchronized (lock) { lock.notifyAll(); }
}
}
//阻塞当前线程,直到锁释放被唤醒,然后尝试获取锁
private int awaitRunStateLock() {
Object lock;
boolean wasInterrupted = false;
//SPINS默认是0
for (int spins = SPINS, r = 0, rs, ns;;) {
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;
}
}
//如果已加锁
else if (r == 0)
//初始化r
r = ThreadLocalRandom.nextSecondarySeed();
else if (spins > 0) {
//自旋等待
r ^= r << 6; r ^= r >>> 21; r ^= r << 7; // xorshift
if (r >= 0)
--spins;
}
//spins等于0
else if ((rs & STARTED) == 0 //线程池未初始化
|| (lock = stealCounter) == null)
Thread.yield(); //执行yeild,等待线程池初始化
//线程池已初始化
else if (U.compareAndSwapInt(this, RUNSTATE, rs, rs | RSIGNAL)) { //状态加上RSIGNAL
synchronized (lock) {
if ((runState & RSIGNAL) != 0) { //再次校验
try {
lock.wait(); //阻塞当前线程
} catch (InterruptedException ie) {
if (!(Thread.currentThread() instanceof
ForkJoinWorkerThread))
wasInterrupted = true;
}
}
else
//如果RSIGNAL标识没了,说明unlockRunState将该标识清除了
//此时还在synchronized代码块中未释放锁,所以unlockRunState中的synchronized会被阻塞
//唤醒所有等待获取锁的线程
lock.notifyAll();
}
//下一次for循环会尝试获取锁
}
}//for循环结束
}