简介
ForkJoin 框架,另一种风格的线程池(相比于ThreadPoolExecutor),采用分治算法,工作密取策略,极大地提高了并行性。对于那种大任务分割小任务的场景(分治)尤其有用。
框架图
几个角色
- ForkJoinTask: 有3个实现,分别是RecursiveTask,RecursiveAction,CountedCompleter.
- RecursiveTask: 可以递归执行的ForkJoinTask。
- RecursiveAction: 无返回值的RecursiveTask。
- CountedCompleter: 任务执行完成后,触发执行自定义钩子函数。
- ForkJoinWorkerThread: 运行 ForkJoinTask 任务的工作线程。
- WorkQueue: 任务队列,支持LIFO(last-in-first-out)的push和pop操作(top端),和FIFO(first-in-first-out)的poll操作(base端),队栈二相性。
- WorkQueue[]: ForkJoinPool 中的任务分为两种,一种是本地提交的任务Submission task,通过execute()、submit()、invoke()等方法提交的任务;另外一种是工作线程fork出的子任务Worker task.
两种任务都会存放在WorkQueue数组中,Submission task存放在WorkQueue数组的偶数索引位置,Worker task存放在奇数索引位置。工作线程只会分配在奇数索引的工作队列。
基本算法
1 protected Long compute() { 2 if (end - start <= THRESHOLD) { 3 return justCompute(); 4 } else { 5 left.fork(); 6 right.fork(); 7 return right.join() + left.join(); 8 } 9 }
源码解析
数据结构
ForkJoinWorkerThreadFactory
线程工厂接口,用于创建工作线程ForkJoinWorkerThread,默认实现是DefaultForkJoinWorkerThreadFactory.
WorkQueue
work-stealing 模式的双端任务队列(内部是数组实现,ForkJoinTask<?>[] array)。
-
工作线程调用fork()方法将分解的任务入队(栈),处于top端(栈顶),工作线程处理自己工作队列的任务时,从栈顶取任务。
- 工作线程也会窃取别的队列的任务,从base端获取。
内部属性
1 static final int INITIAL_QUEUE_CAPACITY = 1 << 13; // 初始队列容量 2 static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 最大队列容量 3 volatile int scanState; // 扫描状态, <0: inactive; 奇数:scanning; 偶数:running 4 int stackPred; // 前任池(WorkQueue[])索引,由此构成一个栈 5 int nsteals; // 偷取的任务个数 6 int hint; // 记录偷取者的索引 7 int config; // pool index | mode 8 volatile int qlock; // 1: locked, < 0: terminate; else 0 9 volatile int base; // 栈底/队列头 10 int top; // 栈顶/队列尾 11 ForkJoinTask<?>[] array; // 任务数组 12 final ForkJoinPool pool; // the containing pool (may be null) 13 final ForkJoinWorkerThread owner; // 当前工作队列的工作线程,共享模式下为null 14 volatile Thread parker; // 调用park阻塞期间为owner,其他情况为null 15 volatile ForkJoinTask<?> currentJoin; // 记录当前join来的任务 16 volatile ForkJoinTask<?> currentSteal; // 记录从其他工作队列偷取过来的任务
ForkJoinTask
有3个实现,分别是RecursiveTask,RecursiveAction,CountedCompleter.
RecursiveTask: 可以递归执行的ForkJoinTask。
RecursiveAction: 无返回值的RecursiveTask。
CountedCompleter: 任务执行完成后,触发执行自定义钩子函数。
1 volatile int status; // 任务状态 2 static final int DONE_MASK = 0xf0000000; // 任务完成掩码 3 static final int NORMAL = 0xf0000000; // 正常,负数 4 static final int CANCELLED = 0xc0000000; // 取消,< NORMAL 5 static final int EXCEPTIONAL = 0x80000000; // 异常,< CANCELLED 6 static final int SIGNAL = 0x00010000; // 通知状态, >= 1 << 16 7 static final int SMASK = 0x0000ffff; // 低位掩码
EmptyTask
核心参数
1 static final int SMASK = 0xffff; // 低16位掩码,最大索引位 2 static final int MAX_CAP = 0x7fff; // 工作线程最大容量 3 static final int EVENMASK = 0xfffe; // 偶数低位掩码 4 static final int SQMASK = 0x007e; // 最多64个偶数槽位(0x007e = 0111 1110,有效的是中间6个1的位置,111111 = 63,再加上000000(0槽位),总共64个) 5 6 static final int SCANNING = 1; // 标记正在scan任务 7 static final int INACTIVE = 1 << 31; // 未活动状态 8 static final int SS_SEQ = 1 << 16; // 版本号(防止CAS的ABA问题) 9 10 static final int MODE_MASK = 0xffff << 16; // int高16位掩码 11 static final int LIFO_QUEUE = 0; // LIFO模式 12 static final int FIFO_QUEUE = 1 << 16; // FIFO模式 13 static final int SHARED_QUEUE = 1 << 31; // 共享模式 14 15 public static final ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory; // 线程创建工厂 16 17 private static final RuntimePermission modifyThreadPermission; // 修改(启动或kill)线程所需要的权限 18 19 static final ForkJoinPool common; // 公共线程池 20 21 static final int commonParallelism; // 并行度 22 23 private static int commonMaxSpares; // 备用线程数 24 25 private static int poolNumberSequence; // 线程名称相关 26 27 private static final synchronized int nextPoolId() { 28 return ++poolNumberSequence; 29 } 30 31 private static final long IDLE_TIMEOUT = 2000L * 1000L * 1000L; // 2sec 32 33 private static final long TIMEOUT_SLOP = 20L * 1000L * 1000L; // 20ms 34 35 private static final int DEFAULT_COMMON_MAX_SPARES = 256; // 默认备用线程数 36 37 private static final int SPINS = 0; // 自旋,暂未使用 38 39 private static final int SEED_INCREMENT = 0x9e3779b9; //indexSeed的增量 40 41 private static final long SP_MASK = 0xffffffffL; // 低32位掩码 42 private static final long UC_MASK = ~SP_MASK; // 高32位掩码 43 44 private static final int AC_SHIFT = 48; // 活跃线程shift 45 private static final long AC_UNIT = 0x0001L << AC_SHIFT; // 活跃线程增量单位 46 private static final long AC_MASK = 0xffffL << AC_SHIFT; // 活跃线程掩码 47 48 private static final int TC_SHIFT = 32; // 工作线程shift 49 private static final long TC_UNIT = 0x0001L << TC_SHIFT; // 工作线程增量单位 50 private static final long TC_MASK = 0xffffL << TC_SHIFT; // 工作线程掩码 51 private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // 创建工作线程的标记 52 53 // 线程池的状态 54 private static final int RSLOCK = 1; // 锁定 55 private static final int RSIGNAL = 1 << 1; // 通知 56 private static final int STARTED = 1 << 2; // 开始 57 private static final int STOP = 1 << 29; // 停止 58 private static final int TERMINATED = 1 << 30; // 终止 59 private static final int SHUTDOWN = 1 << 31; // 关闭 60 61 volatile long ctl; // 主控参数 62 volatile int runState; // 线程池运行状态 63 final int config; // 并行度 | 模式 64 int indexSeed; // 用于生成工作线程索引 65 volatile WorkQueue[] workQueues; // 池 66 final ForkJoinWorkerThreadFactory factory; // 线程工厂 67 final UncaughtExceptionHandler ueh; // 每个工作线程的异常信息 68 final String workerNamePrefix; // 用于创建工作线程的名称 69 volatile AtomicLong stealCounter; // 偷取任务总数,也可作为同步监视器
ctl
字段ctl是ForkJoinPool的核心状态,它是一个64位的long类型数值,包含4个16位子字段:
AC: 活动的工作线程数量减去目标并行度(目标并行度:最大的工作线程数量,所以AC一般是负值,等于0时,说明活动线程已经达到饱和了)
TC: 总的工作线程数量总数减去目标并行度(TC一般也是负值,等于0时,说明总的工作线程已经饱和,并且,AC一般小于等于TC)
SS: 栈顶工作线程状态和版本数(每一个线程在挂起时都会持有前一个等待线程所在工作队列的索引,由此构成一个等待的工作线程栈,栈顶是最新等待的线程,第一位表示状态1.不活动 0.活动,后15表示版本号,标识ID的版本-最后16位)。
ID: 栈顶工作线程所在工作队列的池索引。
这样设计的好处是,通过观察AC或TC的符号(正负)就可以判断(活动|总)工作线程是否达到并行度。令sp = (int)ctl, sp取ctl的后32位,即SS|ID,如果sp非0,则可知有等待的工作线程。
runState
- STARTED 1
- STOP 1 << 1
- TERMINATED 1<<2
- SHUTDOWN 1<<29
- RSLOCK 1<<30
- RSIGNAL 1<<31
runState记录了线程池的运行状态,特别地,除了SHUTDOWN是负数外,其他值都是正数,RSLOCK和RSIGNAL是跟锁相关。
关键方法
提交任务
execute(ForkJoinTask<?>)/submit(ForkJoinTask<?>)/invoke(ForkJoinTask<?>)
1 public void execute(ForkJoinTask<?> task) { // 只提交任务 2 if (task == null) 3 throw new NullPointerException(); 4 externalPush(task); 5 } 6 7 public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) { // 提交并立刻返回任务,ForkJoinTask实现了Future,支持异步取消等操作 8 if (task == null) 9 throw new NullPointerException(); 10 externalPush(task); 11 return task; 12 } 13 14 public <T> T invoke(ForkJoinTask<T> task) { // 提交任务,并等待返回执行结果 15 if (task == null) 16 throw new NullPointerException(); 17 externalPush(task); 18 return task.join(); 19 }
这三个方法都调用了externalPush(ForkJoinTask<?> task)方法,均属于外部提交,置于偶数索引工作队列。
externalPush(ForkJoinTask<?> task)
1 final void externalPush(ForkJoinTask<?> task) { 2 WorkQueue[] ws; 3 WorkQueue q; 4 int m; 5 int r = ThreadLocalRandom.getProbe(); // 探针值,用于计算WorkQueue槽位索引 6 int rs = runState; 7 if ((ws = workQueues) != null // 线程池不为空 8 && (m = (ws.length - 1)) >= 0 // 线程池长度大于0 9 && (q = ws[m & r & SQMASK]) != null // 获取偶数槽位的WorkQueue, m & r & SQMASK, m是全1的掩码,r是随机值,SQMASK(0x7E)偶数,与之与也是偶数 10 && r != 0 // 探针值不为0 11 && rs > 0 // 线程池状态大于0,SHUTDOWN < 0 12 && U.compareAndSwapInt(q, QLOCK, 0, 1)) { // 0 -> 1获得锁 13 ForkJoinTask<?>[] a; 14 int am, n, s; 15 if ((a = q.array) != null // 任务队列(数组)不为空 16 && (am = a.length - 1) > (n = (s = q.top) - q.base)) { // 且数组长度大于任务个数,不需要扩容 17 int j = ((am & s) << ASHIFT) + ABASE; // 计算任务索引位置 18 U.putOrderedObject(a, j, task); // 任务入队 19 U.putOrderedInt(q, QTOP, s + 1); // top加1 20 U.putIntVolatile(q, QLOCK, 0); // 1 -> 0解锁 21 if (n <= 1) // 之前任务个数小于等于1(刚巧又被别的线程偷走),那么此槽位上的线程有可能等待,如果大家都没任务,可能都在等待 22 signalWork(ws, q); // 唤醒可能存在的等待线程 23 return; 24 } 25 U.compareAndSwapInt(q, QLOCK, 1, 0); // 任务入队失败,解锁,走完整的添加任务方法 26 } 27 externalSubmit(task); // 如果不满足if条件,则走完整的添加任务方法 28 }
externalSubmit(ForkJoinTask<?> task)
1 private void externalSubmit(ForkJoinTask<?> task) { 2 int r; // 初始化当前线程的探针值,后续用于计算WorkQueue的索引 3 if ((r = ThreadLocalRandom.getProbe()) == 0) { 4 ThreadLocalRandom.localInit(); 5 r = ThreadLocalRandom.getProbe(); 6 } 7 for (;;) { 8 WorkQueue[] ws; 9 WorkQueue q; 10 int rs, m, k; 11 boolean move = false; 12 if ((rs = runState) < 0) { // 如果线程池已经关闭,则去帮助关闭它 13 tryTerminate(false, false); 14 throw new RejectedExecutionException(); 15 } else if ((rs & STARTED) == 0 || ((ws = workQueues) == null || (m = ws.length - 1) < 0)) { // 初始华工作队列池 16 int ns = 0; 17 rs = lockRunState(); // 加锁 18 try { 19 if ((rs & STARTED) == 0) { // 加锁后再次判断线程池的状态,不重复初始化 20 U.compareAndSwapObject(this, STEALCOUNTER, null, new AtomicLong()); // 初始化stealCounter 21 int p = config & SMASK; 22 int n = (p > 1) ? p - 1 : 1; // 保证n是2的幂次方 23 n |= n >>> 1; 24 n |= n >>> 2; 25 n |= n >>> 4; 26 n |= n >>> 8; 27 n |= n >>> 16; 28 n = (n + 1) << 1; 29 workQueues = new WorkQueue[n]; 30 ns = STARTED; // 标记已经启动 31 } 32 } finally { 33 unlockRunState(rs, (rs & ~RSLOCK) | ns); // 释放锁 34 } 35 } else if ((q = ws[k = r & m & SQMASK]) != null) { // 获取随机偶数槽位的WorkQueue 36 if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) { // 锁定当前WorkQueue 37 ForkJoinTask<?>[] a = q.array; // 任务队列 38 int s = q.top; // 栈顶/队列尾部 39 boolean submitted = false; // 标记是否成功提交任务 40 try { 41 if ((a != null && a.length > s + 1 - q.base) || (a = q.growArray()) != null) { // 任务队列(a)若为空,growArray()会初始化 42 int j = (((a.length - 1) & s) << ASHIFT) + ABASE; // 计算内存地址 43 U.putOrderedObject(a, j, task); // push任务 44 U.putOrderedInt(q, QTOP, s + 1); // 更新top值 45 submitted = true; // 标记任务提交成功 46 } 47 } finally { 48 U.compareAndSwapInt(q, QLOCK, 1, 0); // 解锁 49 } 50 if (submitted) { 51 signalWork(ws, q); // 唤醒挂起的线程 52 return; 53 } 54 } 55 move = true; // 操作失败,需要换个槽位,更新探针值 56 } else if (((rs = runState) & RSLOCK) == 0) { // q为空,则需要创建工作队列,在线程池没有锁定的情况下进行,不然之前换其他槽位 57 q = new WorkQueue(this, null); // 初始化工作队列 58 q.hint = r; // 记录偷取者的索引,初始为随机值 59 q.config = k | SHARED_QUEUE; // 索引 | 共享模式 60 q.scanState = INACTIVE; // 未激活 61 rs = lockRunState(); // 加锁 62 if (rs > 0 && (ws = workQueues) != null && k < ws.length && ws[k] == null) 63 ws[k] = q; // 将工作队列焊到池的槽位上 64 unlockRunState(rs, rs & ~RSLOCK); // 释放锁 65 } else 66 move = true; 67 if (move) // 更新探针值 68 r = ThreadLocalRandom.advanceProbe(r); 69 } 70 }
包含3部分
- 如果线程池还没初始化,则初始化线程池,长度是2的幂次方,期间需锁定runState
- 如果选中的槽位为空(没有工作队列入驻),则初始桦一个工作队列(共享模式的,因为是外部提交,偶数索引),初始是为激活状态,还没投入使用,设置到池里时需锁定runState
- 如果选中的槽位不为空,则获得任务队列(数组),尝试将任务提交进去,成功则唤醒可能沉睡的线程,并返回,如果失败(可能别的线程抢先一步),则转移槽位。
signalWork(WorkQueue[] ws, WorkQueue q)
1 final void signalWork(WorkQueue[] ws, WorkQueue q) { 2 long c; 3 int sp, i; 4 WorkQueue v; 5 Thread p; 6 while ((c = ctl) < 0L) { // 活跃线程未达到并行度,激活或创建 7 if ((sp = (int) c) == 0) { // 没有空闲的线程 8 if ((c & ADD_WORKER) != 0L) // (c & ADD_WORKER) != 0L,说明TC的最高位为1,为负值,而TC = 总的线程数 - 并行度 < 0,表示总的线程数 < 并行度,说明工作线程的个数还很少 9 tryAddWorker(c); // 尝试添加线程 10 break; // 退出 11 } 12 if (ws == null) // 未开始或已停止 13 break; 14 if (ws.length <= (i = sp & SMASK)) // 空闲线程栈顶端线程的所属工作队列索引(正常来讲,应该小于WorkQueue[]的长度的) 15 break; 16 if ((v = ws[i]) == null) // 正在终止,deregisterWorker方法可使对应槽位置空 17 break; 18 int vs = (sp + SS_SEQ) & ~INACTIVE; // 作为下一个scanState待更新的值(增加了版本号,并且调整为激活状态) 19 int d = sp - v.scanState; // 如果d为0,则说明scanState还为更新过,然后才考虑CAS ctl 20 long nc = (UC_MASK & (c + AC_UNIT)) | (SP_MASK & v.stackPred); // 下一个ctl的值,AC + 1 | 上一个等待线程的索引 21 if (d == 0 && U.compareAndSwapLong(this, CTL, c, nc)) { // CAS ctl 22 v.scanState = vs; // 更新scanState 23 if ((p = v.parker) != null) // 如果线程阻塞了,唤醒它 24 U.unpark(p); 25 break; 26 } 27 if (q != null && q.base == q.top) // 没有任务,直接退出 28 break; 29 } 30 }
创建或唤醒一个工作线程 。
这里有一个疑问
if (ws.length <= (i = sp & SMASK)) 表示已终止,ws的类型是WorkQueue[],取自workQueues,是一早被初始化的,长度是2的幂次方,后续对它的操作是扩容,但没有对它进行缩减操作,所以这个if语句应该永远不为真,不过,这并不影响理解,也不排除这种情况存在的可能性,也是一种保证,毕竟索引大小不能大于数组长度。
tryAddWorker(long c)
1 private void tryAddWorker(long c) { 2 boolean add = false; 3 do { 4 long nc = ((AC_MASK & (c + AC_UNIT)) | (TC_MASK & (c + TC_UNIT))); // 下一个ctl的值,AC和TC都加1 5 if (ctl == c) { // ctl没被其他线程改变 6 int rs, stop; 7 if ((stop = (rs = lockRunState()) & STOP) == 0) // 检查线程池是否停止 8 add = U.compareAndSwapLong(this, CTL, c, nc); // 更新ctl 9 unlockRunState(rs, rs & ~RSLOCK); // 解锁 10 if (stop != 0) // 已经停止,退出 11 break; 12 if (add) { // 更新ctl成功,创建线程 13 createWorker(); 14 break; 15 } 16 } 17 } while (((c = ctl) & ADD_WORKER) != 0L && (int) c == 0); // 重新获取ctl,并且没有达到最大线程数,而且,没有空闲的线程 18 }
createWorker()
1 private boolean createWorker() { 2 ForkJoinWorkerThreadFactory fac = factory; 3 Throwable ex = null; 4 ForkJoinWorkerThread wt = null; 5 try { 6 if (fac != null && (wt = fac.newThread(this)) != null) { // 调用线程工厂创建线程,会去注册线程 7 wt.start(); // 启动线程 8 return true; 9 } 10 } catch (Throwable rex) { 11 ex = rex; 12 } 13 deregisterWorker(wt, ex); // 创建失败,注销线程,更新ctl 14 return false; 15 }
ForkJoinWorkerThread 的构造方法里会调用registerWorker(ForkJoinWorkerThread wt)方法。
registerWorker(ForkJoinWorkerThread wt)
1 final WorkQueue registerWorker(ForkJoinWorkerThread wt) { 2 UncaughtExceptionHandler handler; 3 wt.setDaemon(true); // 设置为守护线程 4 if ((handler = ueh) != null) 5 wt.setUncaughtExceptionHandler(handler); 6 WorkQueue w = new WorkQueue(this, wt); // 创建工作队列 7 int i = 0; // 绑定线程池索引(WorkQueue[]) 8 int mode = config & MODE_MASK; 9 int rs = lockRunState(); // 锁定 10 try { 11 WorkQueue[] ws; 12 int n; 13 if ((ws = workQueues) != null && (n = ws.length) > 0) { 14 int s = indexSeed += SEED_INCREMENT; // 用于生成索引 15 int m = n - 1; 16 i = ((s << 1) | 1) & m; // 奇数 17 if (ws[i] != null) { // 碰撞了,选取别的槽位,找不到就扩容 18 int probes = 0; // 记录是否遍历一遍 19 int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2; // 步长约长度的一半 20 while (ws[i = (i + step) & m] != null) { // 一直寻找,每次增加步长 21 if (++probes >= n) { // 如果遍历一遍,就扩容 22 workQueues = ws = Arrays.copyOf(ws, n <<= 1); // 扩容,每次扩大一倍长度 23 m = n - 1; 24 probes = 0; 25 } 26 } 27 } 28 w.hint = s; // 初始时为随机数 29 w.config = i | mode; 30 w.scanState = i; // 等于索引值 31 ws[i] = w; // 注册 32 } 33 } finally { 34 unlockRunState(rs, rs & ~RSLOCK); // 解锁 35 } 36 wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1))); // 设置名字 37 return w; 38 }
注册线程,为该线程创建一个工作队列,并注册到线程池中的奇数索引上,如果找了一圈没找到,则扩容。
deregisterWorker(ForkJoinWorkerThread wt, Throwable ex)
1 final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) { 2 WorkQueue w = null; 3 if (wt != null && (w = wt.workQueue) != null) { 4 WorkQueue[] ws; // 从WorkQueue[]中起初WorkQueue(wt对应的) 5 int idx = w.config & SMASK; // 取得索引 6 int rs = lockRunState(); // 加锁 7 if ((ws = workQueues) != null && ws.length > idx && ws[idx] == w) 8 ws[idx] = null; // 注销 9 unlockRunState(rs, rs & ~RSLOCK); // 解锁 10 } 11 long c; 12 do { 13 } while (!U.compareAndSwapLong(this, CTL, c = ctl, 14 ((AC_MASK & (c - AC_UNIT)) | (TC_MASK & (c - TC_UNIT)) | (SP_MASK & c)))); // AC和TC都减1 15 if (w != null) { 16 w.qlock = -1; // 标记终止 17 w.transferStealCount(this); 18 w.cancelAll(); // 取消剩下的任务 19 } 20 for (;;) { // 可能的替换操作 21 WorkQueue[] ws; 22 int m, sp; 23 if (tryTerminate(false, false) || w == null || w.array == null || (runState & STOP) != 0 24 || (ws = workQueues) == null || (m = ws.length - 1) < 0) // 如果线程池已经终止,跳出循环 25 break; 26 if ((sp = (int) (c = ctl)) != 0) { // 如果有空闲线程,则唤醒一个线程替代已经注销的线程 27 if (tryRelease(c, ws[sp & m], AC_UNIT)) // 唤醒线程 28 break; 29 } else if (ex != null && (c & ADD_WORKER) != 0L) { // 如果没有空闲线程,并且没有达到并行度,创建一个 30 tryAddWorker(c); 31 break; 32 } else 33 break; 34 } 35 if (ex == null) // 异常处理 36 ForkJoinTask.helpExpungeStaleExceptions(); 37 else 38 ForkJoinTask.rethrow(ex); 39 }
从线程池里注销线程,ws[idx] = null; // 注销,更新CTL,根据线程池的状态决定是否找一个自己的替代者(如果有空闲线程,则唤醒一个,否则,创建一个新的工作线程)
runWorker(WorkQueue w)
1 final void runWorker(WorkQueue w) { 2 w.growArray(); 3 int seed = w.hint; 4 int r = (seed == 0) ? 1 : seed; 5 for (ForkJoinTask<?> t;;) { 6 if ((t = scan(w, r)) != null) // 扫描任务 7 w.runTask(t); // 执行任务 8 else if (!awaitWork(w, r)) // 没有任务执行,等待 9 break; 10 r ^= r << 13; 11 r ^= r >>> 17; 12 r ^= r << 5; // 更新随机值 13 } 14 }
- 扫描任务,扫描到一个任务,则执行此任务
- 如果没有扫描到任务,则调用awaitWork方法,返回true则继续参与扫描工作,否则任由其停止
scan(WorkQueue w, int r)
1 private ForkJoinTask<?> scan(WorkQueue w, int r) { 2 WorkQueue[] ws; 3 int m; 4 if ((ws = workQueues) != null && (m = ws.length - 1) > 0 && w != null) { 5 int ss = w.scanState; 6 for (int origin = r & m, k = origin, oldSum = 0, checkSum = 0;;) { // 初始起点为r,随机数 7 WorkQueue q; 8 ForkJoinTask<?>[] a; 9 ForkJoinTask<?> t; 10 int b, n; 11 long c; 12 if ((q = ws[k]) != null) { // 如果k槽位不为空,尝试从该任务队列里取任务 13 if ((n = (b = q.base) - q.top) < 0 && (a = q.array) != null) { // 有任务 14 long i = (((a.length - 1) & b) << ASHIFT) + ABASE; // 内存地址 15 if ((t = ((ForkJoinTask<?>) U.getObjectVolatile(a, i))) != null && q.base == b) { // 获取i地址的内容(任务) 16 if (ss >= 0) { // 如果active,更新array数组i索引处为空,表示任务已经取走,并更新base的值 17 if (U.compareAndSwapObject(a, i, t, null)) { 18 q.base = b + 1; 19 if (n < -1) // 通知其他线程 20 signalWork(ws, q); 21 return t; 22 } 23 } else if (oldSum == 0 && // 如果inactive,尝试active 24 w.scanState < 0) 25 tryRelease(c = ctl, ws[m & (int) c], AC_UNIT); // 激活栈顶工作线程对应的工作队列(任务队列,inactive -> active) 26 } 27 if (ss < 0) // 获取任务失败,重来,更新ss为最新的scanState 28 ss = w.scanState; 29 r ^= r << 1; // 更新随机值 30 r ^= r >>> 3; 31 r ^= r << 10; 32 origin = k = r & m; // 重新扫描 33 oldSum = checkSum = 0; 34 continue; 35 } 36 checkSum += b; 37 } 38 if ((k = (k + 1) & m) == origin) { // 最后没有扫描到任务,准备inactive此工作队列 39 if ((ss >= 0 || (ss == (ss = w.scanState))) && oldSum == (oldSum = checkSum)) { 40 if (ss < 0 || w.qlock < 0) // 已经inactive,跳出 41 break; 42 int ns = ss | INACTIVE; // 尝试inactive 43 long nc = ((SP_MASK & ns) | (UC_MASK & ((c = ctl) - AC_UNIT))); // AC减1,更新ctl 44 w.stackPred = (int) c; // 保存原栈顶工作队列索引 45 U.putInt(w, QSCANSTATE, ns); // 设置scanState 46 if (U.compareAndSwapLong(this, CTL, c, nc)) // CAS ctl 47 ss = ns; // ss取最新的scanState 48 else 49 w.scanState = ss; // CAS ctl失败,设置回scanState 50 } 51 checkSum = 0; 52 } 53 } 54 } 55 return null; 56 }
从随机的索引开始扫描任务,如果拿到任务,唤醒其他线程;如果没有拿到,并且已经扫描一圈了,尝试inactive自己所在的工作队列。
awaitWork(WorkQueue w, int r)
1 private boolean awaitWork(WorkQueue w, int r) { 2 if (w == null || w.qlock < 0) // w已经终止,返回false,不再扫描任务 3 return false; 4 for (int pred = w.stackPred, spins = SPINS, ss;;) { 5 if ((ss = w.scanState) >= 0) // 如果已经active,跳出,返回true,继续扫描任务 6 break; 7 else if (spins > 0) { // 如果spins > 0,自旋等待 8 r ^= r << 6; 9 r ^= r >>> 21; 10 r ^= r << 7; 11 if (r >= 0 && --spins == 0) { // 随机消耗自旋次数 12 WorkQueue v; 13 WorkQueue[] ws; 14 int s, j; 15 AtomicLong sc; 16 if (pred != 0 // 除了自己,还有等待的线程-工作队列 17 && (ws = workQueues) != null // 线程池还在 18 && (j = pred & SMASK) < ws.length // 前任索引还在池范围内 19 && (v = ws[j]) != null // 前任任务队列还在 20 && (v.parker == null || v.scanState >= 0)) // 前任线程已经唤醒,且工作队列已经激活 21 spins = SPINS; // 上面的一系列判断表明,很快就有任务了,先不park,继续自旋 22 } 23 } else if (w.qlock < 0) // 自旋之后,再次检查工作队列是否终止,若是,退出扫描 24 return false; 25 else if (!Thread.interrupted()) { // 如果线程中断了,清除中断标记,不考虑park,否则进入该分支 26 long c, prevctl, parkTime, deadline; 27 int ac = (int) ((c = ctl) >> AC_SHIFT) + (config & SMASK); // 计算活跃线程的个数 28 if ((ac <= 0 && tryTerminate(false, false)) || (runState & STOP) != 0) // 线程池正在终止,退出扫描 29 return false; 30 if (ac <= 0 && ss == (int) c) { // 自己是栈顶等待者 31 prevctl = (UC_MASK & (c + AC_UNIT)) | (SP_MASK & pred); // 设置为前一次的ctl 32 int t = (short) (c >>> TC_SHIFT); // 总的线程数 33 if (t > 2 && U.compareAndSwapLong(this, CTL, c, prevctl)) // 总线程数过多,直接退出扫描 34 return false; 35 parkTime = IDLE_TIMEOUT * ((t >= 0) ? 1 : 1 - t); // 计算等待时间 36 deadline = System.nanoTime() + parkTime - TIMEOUT_SLOP; 37 } else 38 prevctl = parkTime = deadline = 0L; 39 Thread wt = Thread.currentThread(); 40 U.putObject(wt, PARKBLOCKER, this); // 加锁 41 w.parker = wt; // 设置parker,准备阻塞 42 if (w.scanState < 0 && ctl == c) // 阻塞前再次检查状态 43 U.park(false, parkTime); 44 U.putOrderedObject(w, QPARKER, null); // 唤醒后,置空parker 45 U.putObject(wt, PARKBLOCKER, null); // 解锁 46 if (w.scanState >= 0) // 已激活,跳出继续扫描 47 break; 48 if (parkTime != 0L && ctl == c && deadline - System.nanoTime() <= 0L 49 && U.compareAndSwapLong(this, CTL, c, prevctl)) // 超时,未等到任务,跳出,不再执行扫描任务,削减工作线程 50 return false; // shrink pool 51 } 52 } 53 return true; 54 }
若为扫描到任务,则会执行此方法。
- 首先会自旋等待,自旋过程中如果发现前任线程已经唤醒,且工作队列已经激活,说明已经有任务了,接着自旋等待
- 若发现工作队列已经终止,则返回false,表示自己退出扫描工作
- 如果线程中断了,清除中断标记,不考虑park,否则,进行下面一系列操作
- 如果发现当前线程数量过多,则直接返回false,自己不再参与扫描工作
- 计算阻塞时间,准备阻塞自己
- 阻塞前或唤醒后,都会判断线程池的状态,工作队列的状态,以判断自己是否继续参与扫描工作
fork()
1 public final ForkJoinTask<V> fork() { // 从top端压入任务 2 Thread t; 3 if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) 4 ((ForkJoinWorkerThread)t).workQueue.push(this); // 当前工作线程所在的工作队列 5 else 6 ForkJoinPool.common.externalPush(this); // 外部提交任务 7 return this; 8 }
join()
1 public final V join() { // 调用doJoin() 2 int s; 3 if ((s = doJoin() & DONE_MASK) != NORMAL) 4 reportException(s); 5 return getRawResult(); 6 }
doJoin()
1 private int doJoin() { 2 int s; 3 Thread t; 4 ForkJoinWorkerThread wt; 5 ForkJoinPool.WorkQueue w; 6 return (s = status) < 0 ? s 7 : ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) 8 ? (w = (wt = (ForkJoinWorkerThread) t).workQueue).tryUnpush(this) && (s = doExec()) < 0 ? s 9 : wt.pool.awaitJoin(w, this, 0L) 10 : externalAwaitDone(); 11 }
转换成下面的形式更好看点
1 private int doJoin() { 2 int s; 3 Thread t; 4 ForkJoinWorkerThread wt; 5 ForkJoinPool.WorkQueue w; 6 7 if((s = status) < 0) { // 已经有结果,直接返回 8 return s; 9 }else { 10 if((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) { // 如果是工作线程 11 if((w = (wt = (ForkJoinWorkerThread) t).workQueue).tryUnpush(this) // 尝试从本工作队列里取出等待的任务 12 && (s = doExec()) < 0) { // 如果取出了任务,则去执行它,并返回结果 13 return s; 14 }else { 15 return wt.pool.awaitJoin(w, this, 0L); // 否则,可能有别的线程把这个任务偷走了,执行内部等待方法 16 } 17 }else { // 如果是外部线程,执行外部等待方法 18 return externalAwaitDone(); 19 } 20 } 21 22 }
externalAwaitDone()
1 private int externalAwaitDone() { 2 int s = ((this instanceof CountedCompleter) ? // 如果是CountedCompleter类型的任务,执行externalHelpComplete方法 3 ForkJoinPool.common.externalHelpComplete((CountedCompleter<?>) this, 0) 4 : ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : 0); // 否则,执行tryExternalUnpush方法,成功则执行任务,否则,返回0 5 if (s >= 0 && (s = status) >= 0) { // 如果任务没有结束,则等待 6 boolean interrupted = false; 7 do { 8 if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) { // 将status设置为SIGNAL,等着被notify 9 synchronized (this) { 10 if (status >= 0) { // 任务未结束 11 try { 12 wait(0L); // 等待 13 } catch (InterruptedException ie) { 14 interrupted = true; // 记录中断标记 15 } 16 } else 17 notifyAll(); // 任务已经结束,通知等待的线程 18 } 19 } 20 } while ((s = status) >= 0); // 任务未结束,就一直等待 21 if (interrupted) 22 Thread.currentThread().interrupt(); // 补上中断 23 } 24 return s; 25 }
tryExternalUnpush(ForkJoinTask<?> task)
1 final boolean tryExternalUnpush(ForkJoinTask<?> task) { 2 WorkQueue[] ws; 3 WorkQueue w; 4 ForkJoinTask<?>[] a; 5 int m, s; 6 int r = ThreadLocalRandom.getProbe(); 7 if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 && (w = ws[m & r & SQMASK]) != null 8 && (a = w.array) != null && (s = w.top) != w.base) { 9 long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE; 10 if (U.compareAndSwapInt(w, QLOCK, 0, 1)) { 11 if (w.top == s && w.array == a && U.getObject(a, j) == task 12 && U.compareAndSwapObject(a, j, task, null)) { // 如果task在任务队列的top位置,则返回true; 否则,返回false 13 U.putOrderedInt(w, QTOP, s - 1); 14 U.putOrderedInt(w, QLOCK, 0); 15 return true; 16 } 17 U.compareAndSwapInt(w, QLOCK, 1, 0); 18 } 19 } 20 return false; 21 }
tryUnpush(ForkJoinTask<?> t)
1 final boolean tryUnpush(ForkJoinTask<?> t) { // 任务t在array的top位时,返回true; 否则,返回false 2 ForkJoinTask<?>[] a; 3 int s; 4 if ((a = array) != null && (s = top) != base 5 && U.compareAndSwapObject(a, (((a.length - 1) & --s) << ASHIFT) + ABASE, t, null)) { 6 U.putOrderedInt(this, QTOP, s); 7 return true; 8 } 9 return false; 10 }
doExec()
1 final int doExec() { 2 int s; 3 boolean completed; 4 if ((s = status) >= 0) { 5 try { 6 completed = exec(); // 执行具体的任务 7 } catch (Throwable rex) { 8 return setExceptionalCompletion(rex); 9 } 10 if (completed) 11 s = setCompletion(NORMAL); 12 } 13 return s; 14 }
awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline)
1 final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) { 2 int s = 0; 3 if (task != null && w != null) { 4 ForkJoinTask<?> prevJoin = w.currentJoin; // 记录上一个join的任务 5 U.putOrderedObject(w, QCURRENTJOIN, task); // 设置task为当前join的任务 6 CountedCompleter<?> cc = (task instanceof CountedCompleter) ? (CountedCompleter<?>) task : null; 7 for (;;) { 8 if ((s = task.status) < 0) // 任务已经结束,跳出循环 9 break; 10 if (cc != null) 11 helpComplete(w, cc, 0); // CountedCompleter类型的任务调用helpComplete()方法 12 else if (w.base == w.top || w.tryRemoveAndExec(task)) // 任务队列为空或执行失败(任务被别的线程偷走了),帮助偷取者执行该任务 13 helpStealer(w, task); 14 if ((s = task.status) < 0) // 任务已经结束,跳出循环 15 break; 16 long ms, ns; 17 if (deadline == 0L) // 任务等待时间 18 ms = 0L; 19 else if ((ns = deadline - System.nanoTime()) <= 0L) // 超时退出 20 break; 21 else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L) 22 ms = 1L; 23 if (tryCompensate(w)) { // 尝试补偿策略(找一个替代者执行任务,自己在这儿等) 24 task.internalWait(ms); // 补偿成功,等待指定时间 25 U.getAndAddLong(this, CTL, AC_UNIT); // 活跃线程加1 26 } 27 } 28 U.putOrderedObject(w, QCURRENTJOIN, prevJoin); // 设置回前一个join的任务 29 } 30 return s; 31 }
tryRemoveAndExec(ForkJoinTask<?> task)
1 final boolean tryRemoveAndExec(ForkJoinTask<?> task) { // 该方法返回true, 代表可以去偷取任务执行了;否则,继续等待 2 ForkJoinTask<?>[] a; 3 int m, s, b, n; 4 if ((a = array) != null && (m = a.length - 1) >= 0 && task != null) { 5 while ((n = (s = top) - (b = base)) > 0) { // 从top开始,遍历任务队列,查找是否存在给定task 6 for (ForkJoinTask<?> t;;) { 7 long j = ((--s & m) << ASHIFT) + ABASE; // 计算任务内存地址,s递减 8 if ((t = (ForkJoinTask<?>) U.getObject(a, j)) == null) // 如果任务为空, 9 return s + 1 == top; // 如果top位为空,说明任务队列已经空了,返回true 10 else if (t == task) { // 找到给定任务task 11 boolean removed = false; 12 if (s + 1 == top) { // 任务在top位置,直接弹出pop 13 if (U.compareAndSwapObject(a, j, task, null)) { 14 U.putOrderedInt(this, QTOP, s); 15 removed = true; 16 } 17 } else if (base == b) // 如果不是在top,使用EmptyTask填补此位置 18 removed = U.compareAndSwapObject(a, j, task, new EmptyTask()); 19 if (removed) 20 task.doExec(); // 执行任务 21 break; // 跳出,继续检查task.status,判断任务是否结束 22 } else if (t.status < 0 && s + 1 == top) { // 任务结束(取消),且目前检查的是top 23 if (U.compareAndSwapObject(a, j, t, null)) // 检查task是否在top位,如果是并置空top位,更新top为s(top - 1) 24 U.putOrderedInt(this, QTOP, s); 25 break; // 任务取消了 26 } 27 if (--n == 0) // 遍历结束 28 return false; 29 } 30 if (task.status < 0) // 任务结束 31 return false; 32 } 33 } 34 return true; 35 }
从top位置开始向下遍历任务,如果找到给定任务,把它从当前Worker的任务队列中移除并执行,移除的位置使用EmptyTask代替。如果任务队列为空或者任务未执行完毕返回true;任务执行完毕返回false.
helpStealer(WorkQueue w, ForkJoinTask<?> task)
1 private void helpStealer(WorkQueue w, ForkJoinTask<?> task) { // 帮助偷取者(偷取自己任务的线程)执行任务 2 WorkQueue[] ws = workQueues; 3 int oldSum = 0, checkSum, m; 4 if (ws != null && (m = ws.length - 1) >= 0 && w != null && task != null) { 5 do { // restart point 6 checkSum = 0; // for stability check 7 ForkJoinTask<?> subtask; 8 WorkQueue j = w, v; // v是子任务的偷取者 9 descent: for (subtask = task; subtask.status >= 0;) { // 从目标任务开始,记录当前Join的任务,也包括偷取者当前Join的任务,递归帮助 10 for (int h = j.hint | 1, k = 0, i;; k += 2) { // 每次跳2个,遍历奇数位索引 11 if (k > m) // 如果遍历一遍没有找到偷取者,跳出循环 12 break descent; 13 if ((v = ws[i = (h + k) & m]) != null) { 14 if (v.currentSteal == subtask) { // 定位到偷取者,更新hint为偷取者索引,方便下次定位 15 j.hint = i; 16 break; 17 } 18 checkSum += v.base; // 若没有定位到,则累加工作队列的base值,继续遍历 19 } 20 } 21 for (;;) { // 帮助偷取者执行任务 22 ForkJoinTask<?>[] a; // 偷取者的任务数组 23 int b; 24 checkSum += (b = v.base); // 累加偷取者的base值 25 ForkJoinTask<?> next = v.currentJoin; // 记录偷取者Join的任务 26 if (subtask.status < 0 || j.currentJoin != subtask || v.currentSteal != subtask) // subtask结束,或者数据不一致了(j.currentJoin != subtask || v.currentSteal != subtask) 27 break descent; // 跳出外层循环重来 28 if (b - v.top >= 0 || (a = v.array) == null) { // 偷取者的任务列表为空 29 if ((subtask = next) == null) // 偷取者的Join任务为空,跳出外层循环 30 break descent; 31 j = v; // 否则,j取v的值(j指向被偷者,v指向偷取者),且subtask指向next Join任务 32 break; // 继续遍历,寻找偷取者的偷取者(递归) 33 } 34 int i = (((a.length - 1) & b) << ASHIFT) + ABASE; // 偷取者的base内存地址 35 ForkJoinTask<?> t = ((ForkJoinTask<?>) U.getObjectVolatile(a, i)); // 获取base位置任务 36 if (v.base == b) { 37 if (t == null) // 任务为空,跳出外层循环(可能被别的线程拿走了) 38 break descent; 39 if (U.compareAndSwapObject(a, i, t, null)) { // poll(从base位置取出任务) 40 v.base = b + 1; // 更新base的值 41 ForkJoinTask<?> ps = w.currentSteal; // 记录调用者之前偷取的任务 42 int top = w.top; // 记录调用者的top值 43 do { 44 U.putOrderedObject(w, QCURRENTSTEAL, t); // 更新currentSteal为刚刚偷取到的任务 45 t.doExec(); // 指向任务 46 } while (task.status >= 0 && w.top != top && (t = w.pop()) != null); // 如果任务未结束,且自己任务队列不为空,优先处理自己队列里的任务 47 U.putOrderedObject(w, QCURRENTSTEAL, ps); // 把之前偷取的任务设置回currentSteal 48 if (w.base != w.top) // 自己队列来新任务了,直接返回 49 return; 50 } 51 } 52 } 53 } 54 } while (task.status >= 0 && oldSum != (oldSum = checkSum)); // Join的任务未结束,且任务在流动中,继续帮助执行 55 } 56 }
- 每次跳2个槽位,遍历奇数位索引,直到定位到偷取者,并记录偷取者的索引(hint = i),方便下次定位。
- 获取偷取者的任务列表,帮助其执行任务,如果执行过程中发现自己任务列表里有任务,则依次弹出执行。
- 如果偷取者任务队列为空,则帮助其执行Join任务,寻找偷取者的偷取者,如此往复,加快任务执行。
- 如果最后发现自己任务队列不为空(base != top),则退出帮助。
- 最后判断任务task是否结束,如果未结束,且工作队列base和在变动中,说明偷取任务一直在进行,则重复以上操作,加快任务执行。
tryCompensate(WorkQueue w)
1 private boolean tryCompensate(WorkQueue w) { // 找一个替代者执行任务,自己等待任务结束 2 boolean canBlock; 3 WorkQueue[] ws; 4 long c; 5 int m, pc, sp; 6 if (w == null || w.qlock < 0 // 调用者正在终止 7 || (ws = workQueues) == null || (m = ws.length - 1) <= 0 // 线程池结束 8 || (pc = config & SMASK) == 0) // 并行度为0(不可用) 9 canBlock = false; // 不可阻塞 10 else if ((sp = (int) (c = ctl)) != 0) // 如果有空闲线程,释放空闲线程 11 canBlock = tryRelease(c, ws[sp & m], 0L); 12 else { // 没有空闲线程,尝试创建一个 13 int ac = (int) (c >> AC_SHIFT) + pc; // 活跃线程数 14 int tc = (short) (c >> TC_SHIFT) + pc; // 总的线程数 15 int nbusy = 0; // 验证饱和度(Running线程数是否等于总的线程数) 16 for (int i = 0; i <= m; ++i) { 17 WorkQueue v; 18 if ((v = ws[((i << 1) | 1) & m]) != null) { // 遍历两遍奇数索引槽位 19 if ((v.scanState & SCANNING) != 0) 20 break; 21 ++nbusy; 22 } 23 } 24 if (nbusy != (tc << 1) || ctl != c) // 遍历两遍奇数索引槽位,tc需要乘以2 25 canBlock = false; // 并不是所有的线程都在干活,或者数据(ctl)失效,不要阻塞 26 else if (tc >= pc && ac > 1 && w.isEmpty()) { // 总线程数大于并行度 && 活动线程数大于1 && 调用者任务队列为空 27 long nc = ((AC_MASK & (c - AC_UNIT)) | (~AC_MASK & c)); // AC - 1 28 canBlock = U.compareAndSwapLong(this, CTL, c, nc); 29 } else if (tc >= MAX_CAP || (this == common && tc >= pc + commonMaxSpares)) // TC达到最大容量 30 throw new RejectedExecutionException("Thread limit exceeded replacing blocked worker"); 31 else { 32 boolean add = false; 33 int rs; 34 long nc = ((AC_MASK & c) | (TC_MASK & (c + TC_UNIT))); // 总的线程数加1,活跃线程数不变(补偿) 35 if (((rs = lockRunState()) & STOP) == 0) 36 add = U.compareAndSwapLong(this, CTL, c, nc); 37 unlockRunState(rs, rs & ~RSLOCK); 38 canBlock = add && createWorker(); // 创建工作线程 39 } 40 } 41 return canBlock; 42 }
- 调用者队列不为空,并且有空闲工作线程,唤醒空闲线程(tryRelease)
- 线程池未停止,活跃线程数不足,新建一个工作线程(createWorker)
- 工作队列正在停止或线程池停止,总线程数大于并行度 && 活动线程数大于1 && 调用者任务队列为空,不需要补偿
awaitQuiescence(long timeout, TimeUnit unit)
1 public boolean awaitQuiescence(long timeout, TimeUnit unit) { // 等待所有的任务执行结束 2 long nanos = unit.toNanos(timeout); 3 ForkJoinWorkerThread wt; 4 Thread thread = Thread.currentThread(); 5 if ((thread instanceof ForkJoinWorkerThread) && (wt = (ForkJoinWorkerThread) thread).pool == this) { 6 helpQuiescePool(wt.workQueue); // 如果是工作线程,帮助执行任务,使其尽快结束 7 return true; 8 } 9 long startTime = System.nanoTime(); 10 WorkQueue[] ws; 11 int r = 0, m; 12 boolean found = true; 13 while (!isQuiescent() && (ws = workQueues) != null && (m = ws.length - 1) >= 0) { // 任务未执行结束 14 if (!found) { // 未找到任务 15 if ((System.nanoTime() - startTime) > nanos) 16 return false; // 超时返回 17 Thread.yield(); // 让出CPU时间片,让其他线程快点干活 18 } 19 found = false; 20 for (int j = (m + 1) << 2; j >= 0; --j) { // j初始值是4 * ws.length, 然后递减,这是要遍历4次的节奏 21 ForkJoinTask<?> t; 22 WorkQueue q; 23 int b, k; 24 if ((k = r++ & m) <= m && k >= 0 && (q = ws[k]) != null && (b = q.base) - q.top < 0) { 25 found = true; 26 if ((t = q.pollAt(b)) != null) // 从base位置取出任务并执行 27 t.doExec(); 28 break; 29 } 30 } 31 } 32 return true; 33 }
helpQuiescePool(WorkQueue w)
1 final void helpQuiescePool(WorkQueue w) { 2 ForkJoinTask<?> ps = w.currentSteal; // 保存当前偷取的任务 3 for (boolean active = true;;) { 4 long c; 5 WorkQueue q; 6 ForkJoinTask<?> t; 7 int b; 8 w.execLocalTasks(); // 首先执行自己队列里的任务 9 if ((q = findNonEmptyStealQueue()) != null) { // 如果查找到非空WorkQueue 10 if (!active) { // 当前是inactive 11 active = true; // 重新设置为active 12 U.getAndAddLong(this, CTL, AC_UNIT); // AC + 1 13 } 14 if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) { // 任务不为空,从base位置取任务 15 U.putOrderedObject(w, QCURRENTSTEAL, t); // 记录t为当前偷取的任务 16 t.doExec(); // 开始干活 17 if (++w.nsteals < 0) // 增加计数 18 w.transferStealCount(this); // 将自己的计数添加到线程池的总计数上面去 19 } 20 } else if (active) { // 是active,但是没找到任务 21 long nc = (AC_MASK & ((c = ctl) - AC_UNIT)) | (~AC_MASK & c); // AC - 1 22 if ((int) (nc >> AC_SHIFT) + (config & SMASK) <= 0) 23 break; // AC为0,退出 24 if (U.compareAndSwapLong(this, CTL, c, nc)) // CAS ctl的值 25 active = false; // inactive 26 } else if ((int) ((c = ctl) >> AC_SHIFT) + (config & SMASK) <= 0 // inactive, AC == 0 27 && U.compareAndSwapLong(this, CTL, c, c + AC_UNIT)) // AC + 1, 保证AC至少为1 28 break; 29 } 30 U.putOrderedObject(w, QCURRENTSTEAL, ps); // 设置回偷取的任务 31 }
awaitTermination(long timeout, TimeUnit unit)
1 public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { 2 if (Thread.interrupted()) 3 throw new InterruptedException(); 4 if (this == common) { 5 awaitQuiescence(timeout, unit); 6 return false; 7 } 8 long nanos = unit.toNanos(timeout); 9 if (isTerminated()) 10 return true; 11 if (nanos <= 0L) 12 return false; 13 long deadline = System.nanoTime() + nanos; 14 synchronized (this) { 15 for (;;) { // 等待线程池终止 16 if (isTerminated()) 17 return true; 18 if (nanos <= 0L) 19 return false; 20 long millis = TimeUnit.NANOSECONDS.toMillis(nanos); 21 wait(millis > 0L ? millis : 1L); 22 nanos = deadline - System.nanoTime(); 23 } 24 } 25 }
tryTerminate(boolean now, boolean enable)
1 private boolean tryTerminate(boolean now, boolean enable) { 2 int rs; 3 if (this == common) // 公共线程池,不能shutdown 4 return false; 5 if ((rs = runState) >= 0) { 6 if (!enable) 7 return false; 8 rs = lockRunState(); // 进入SHUTDOWN阶段 9 unlockRunState(rs, (rs & ~RSLOCK) | SHUTDOWN); 10 } 11 12 if ((rs & STOP) == 0) { // 准备进入STOP阶段 13 if (!now) { // 必要的检查 14 for (long oldSum = 0L;;) { 15 WorkQueue[] ws; 16 WorkQueue w; 17 int m, b; 18 long c; 19 long checkSum = ctl; 20 if ((int) (checkSum >> AC_SHIFT) + (config & SMASK) > 0) 21 return false; // 如果有活动的工作线程,还不能停止 22 if ((ws = workQueues) == null || (m = ws.length - 1) <= 0) 23 break; 24 for (int i = 0; i <= m; ++i) { 25 if ((w = ws[i]) != null) { 26 if ((b = w.base) != w.top || w.scanState >= 0 || w.currentSteal != null) { 27 tryRelease(c = ctl, ws[m & (int) c], AC_UNIT); 28 return false; // 有任务在执行,还不能停止 29 } 30 checkSum += b; // 累加base值 31 if ((i & 1) == 0) 32 w.qlock = -1; // 偶数索引工作队列,qlock = -1, 拦截从外部提交的任务 33 } 34 } 35 if (oldSum == (oldSum = checkSum)) // 稳定了,退出 36 break; 37 } 38 } 39 if ((runState & STOP) == 0) { // 如果now等于true,立刻进入STOP结点 40 rs = lockRunState(); 41 unlockRunState(rs, (rs & ~RSLOCK) | STOP); 42 } 43 } 44 45 int pass = 0; 46 for (long oldSum = 0L;;) { 47 WorkQueue[] ws; 48 WorkQueue w; 49 ForkJoinWorkerThread wt; 50 int m; 51 long checkSum = ctl; 52 if ((short) (checkSum >>> TC_SHIFT) + (config & SMASK) <= 0 || (ws = workQueues) == null 53 || (m = ws.length - 1) <= 0) { // 可以终止了 54 if ((runState & TERMINATED) == 0) { 55 rs = lockRunState(); 56 unlockRunState(rs, (rs & ~RSLOCK) | TERMINATED); // 进入TERMINATED阶段 57 synchronized (this) { 58 notifyAll(); // 唤醒所有线程 59 } 60 } 61 break; // 跳出 62 } 63 for (int i = 0; i <= m; ++i) { 64 if ((w = ws[i]) != null) { 65 checkSum += w.base; 66 w.qlock = -1; // 设置不可用 67 if (pass > 0) { 68 w.cancelAll(); // 取消所有的任务 69 if (pass > 1 && (wt = w.owner) != null) { 70 if (!wt.isInterrupted()) { 71 try { 72 wt.interrupt(); // 中断线程 73 } catch (Throwable ignore) { 74 } 75 } 76 if (w.scanState < 0) 77 U.unpark(wt); // 唤醒线程 78 } 79 } 80 } 81 } 82 if (checkSum != oldSum) { // 不稳定,重来 83 oldSum = checkSum; 84 pass = 0; 85 } else if (pass > 3 && pass > m) // 退出 86 break; 87 else if (++pass > 1) { // 出队 88 long c; 89 int j = 0, sp; 90 while (j++ <= m && (sp = (int) (c = ctl)) != 0) 91 tryRelease(c, ws[sp & m], AC_UNIT); 92 } 93 } 94 return true; 95 }
SHUTDOWN(!common) -> STOP(无任务执行) -> TERMINATED(over)
fork-join
1.有一个大的任务Task(8), 最终被分解成8个小任务Task(1)
2.将Task(8)加入到任务队列里面(偶数索引,图中未显示),线程A偷取到Task(8),fork了2个Task(4),push到任务队列里面
3.pop出Task(4), fork出2个Task(2),push到任务队列里面
4. pop出Task(2), fork出2个Task(1), push到任务队列里面
5.pop出任务Task(1),此刻已经达到最小粒度,开始执行该任务;与此同时,线程B从底部(base)位置steal走了Task(4)
6.线程B拿到Task(4)之后,fork出了2个Task(2),push到任务队列里面
7.线程A执行完自己的任务后,由于Task(4).join(),索性定位到偷走自己任务的线程B所在的工作队列,帮助其执行任务,整体加快任务进度,帮助的方式也是steal
以上是最简单的一种fork.join方式。
行文至此结束。
尊重他人的劳动,转载请注明出处:http://www.cnblogs.com/aniao/p/aniao_fjp.html
来源:https://www.cnblogs.com/aniao/p/aniao_fjp.html