【JUC源码解析】ForkJoinPool

你说的曾经没有我的故事 提交于 2019-11-27 12:07:38

简介

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     }

 

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

这里有一个疑问

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!