【JUC源码解析】ForkJoinPool

简介

线程池,分治,工作密取。

几个角色

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()等方法提交的任务;另外一种是 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; // 记录从其他工作队列偷取过来的任务

EmptyTask

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

核心参数

关键方法

行文至此结束。

尊重他人的劳动,转载请注明出处:http://www.cnblogs.com/aniao/p/aniao_fjp.html

猜你喜欢

转载自www.cnblogs.com/aniao/p/aniao_fjp.html