简介

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

空任务,用于替换队列中join的任务。
前置条件,subTask之前已经通过fork入队(当前线程所属的工作队列/栈)
线程执行当前任务时,碰见subTask.join(),便会去队列里查找subTask,从栈顶开始,如果恰巧栈顶就是subTask,那么直接执行;若是在队列中间找到,我们知道,任务队列内部是数数组(ForkJoinTask<?>[]),所以没法使其他的任务填补这个空缺(若不填补,此位置为null,那么每个任务便多了一个非空判断),所以使用一个EmptyTask填补此位置(当线程拿到这个task时,什么都不用做,因为方法体没内容,索引很快执行下一个任务)。

核心参数

  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. }

创建或唤醒一个工作线程 。

这里有一个疑问

  1. 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,否则,进行下面一系列操作
  1. 如果发现当前线程数量过多,则直接返回false,自己不再参与扫描工作
  2. 计算阻塞时间,准备阻塞自己
  3. 阻塞前或唤醒后,都会判断线程池的状态,工作队列的状态,以判断自己是否继续参与扫描工作

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

【JUC源码解析】ForkJoinPool的更多相关文章

  1. 【JUC源码解析】ScheduledThreadPoolExecutor

    简介 它是一个线程池执行器(ThreadPoolExecutor),在给定的延迟(delay)后执行.在多线程或者对灵活性有要求的环境下,要优于java.util.Timer. 提交的任务在执行之前支 ...

  2. 【JUC源码解析】SynchronousQueue

    简介 SynchronousQueue是一种特殊的阻塞队列,该队列没有容量. [存数据线程]到达队列后,若发现没有[取数据线程]在此等待,则[存数据线程]便入队等待,直到有[取数据线程]来取数据,并释 ...

  3. 【JUC源码解析】DelayQueue

    简介 基于优先级队列,以过期时间作为排序的基准,剩余时间最少的元素排在队首.只有过期的元素才能出队,在此之前,线程等待. 源码解析 属性 private final transient Reentra ...

  4. 【JUC源码解析】CyclicBarrier

    简介 CyclicBarrier,一个同步器,允许多个线程相互等待,直到达到一个公共屏障点. 概述 CyclicBarrier支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后 ...

  5. 【JUC源码解析】ConcurrentLinkedQueue

    简介 ConcurrentLinkedQueue是一个基于链表结点的无界线程安全队列. 概述 队列顺序,为FIFO(first-in-first-out):队首元素,是当前排队时间最长的:队尾元素,当 ...

  6. 【JUC源码解析】Exchanger

    简介 Exchanger,并发工具类,用于线程间的数据交换. 使用 两个线程,两个缓冲区,一个线程往一个缓冲区里面填数据,另一个线程从另一个缓冲区里面取数据.当填数据的线程将缓冲区填满时,或者取数据的 ...

  7. Jdk1.6 JUC源码解析(12)-ArrayBlockingQueue

    功能简介: ArrayBlockingQueue是一种基于数组实现的有界的阻塞队列.队列中的元素遵循先入先出(FIFO)的规则.新元素插入到队列的尾部,从队列头部取出元素. 和普通队列有所不同,该队列 ...

  8. 【JUC源码解析】CompletableFuture

    简介 先说Future, 它用来描述一个异步计算的结果.isDone方法可以用来检查计算是否完成,get方法可以用来获取结果,直到完成前一直阻塞当前线程,cancel方法可以取消任务.而对于结果的获取 ...

  9. 【JUC源码解析】Phaser

    简介 Phaser,阶段器,可作为一个可复用的同步屏障,与CyclicBarrier和CountDownLatch类似,但更强大. 全览图 如上图所示,phaser,支持phaser树(图中,简化为p ...

随机推荐

  1. python升级 (2.6升级到3.5)

    在引用模块pandas时竟然提示不支持2.6, 果断升级,在网上找了很多博客,觉得这个比较清楚(https://blog.csdn.net/my_bai/article/details/7289602 ...

  2. Spring中的统一异常处理方式

    源自:https://segmentfault.com/a/1190000016236188 在具体的SSM项目开发中,由于Controller层为处于请求处理的最顶层,再往上就是框架代码的. 因此, ...

  3. right here waiting的歌词

    right here waiting的歌词 2006-12-30 17:36 匿名 | 分类:音乐 | 该问题已经合并到>> right here waiting的歌词有吗?   扫描二维 ...

  4. #001 CSS快速入门讲解

    CSS入门讲解 HTML人+CSS衣服+JS动作=>DHTML CSS: 层叠样式表 CSS2.0 和 CSS3.0 版本,目前学习CSS2, CSS3只是多了一些样式出来而已 CSS 干啥用的 ...

  5. 个人技术博客二之apk反编译与加密

    根据原文郭霖大神的博客Android安全攻防战,反编译与混淆技术完全解析 本人亲测反编译真的没有什么卵用,个人纯属好奇就去搜了一下,偷窃有罪,抄袭可耻. 1.手机上的apk都是打包好的,直接安装使用. ...

  6. APP案例分析-摩拜单车app

    第二次作业-App案例分析 本次案例分析选用的是 摩拜单车IOS5.7.5版本 测试环境为 IPhone 6s (IOS11.0.1,含有3DTOUCH功能).本次案例分析仅针对APP 而言,并不涉及 ...

  7. ganache-cli

    安装: npm install -g ganache-cli@6.1.8 使用: userdeMacBook-Pro:~ user$ ganache-cli -m "success rifl ...

  8. 【转】纯JS省市区三级联动(行政区划代码更新至2015-9-30)

    本文代码实现的功能是省市区三级联动下拉列表,纯Javascript,网上已有很多这方面的代码.但是作为一个新手,这是我的第一篇CSDN博客,发此文的目的主要是学习交流,希望看到的朋友发现有什么不对的地 ...

  9. Spring Security with Boot

    1.spring安全 boot中的应用文档https://docs.spring.io/spring-security/site/docs/current/guides/html5//hellowor ...

  10. 展开label,利用YYText实现文字显示不完末尾添加全文

    效果图: 操作 先github下载<YYText>文件导入, 代码如下: #import "ViewController.h" #import "YYLabe ...