什么是 ForkJoin
ForkJoin 框架是 Java7 提供的用于并行执行任务的框架,它将大任务分割成若干小任务,最终汇总每个小任务结果后得到大任务结果。
通过 Fork 和 Join 两个单词理解该框架:Fork 指把大任务切分为若干子任务并行执行,Join 指合并这些子任务的执行结果。例如计算 1+2+...+10000,可以分割成 10 个子任务,每个子任务分别对 1000 个数进行求和,最终汇总这 10 个子任务的结果。
使用步骤
第一步分割任务。首先创建一个 Fork 类来把大任务分割成子任务,如果子任务仍然很大,则继续递归分割,直到子任务足够小。
第二步执行任务并合并结果。分割的子任务分别放在双端队列里,多个线程分别从双端队列获取任务执行。子任务执行完的结果统一收集,启动一个线程从队列拿数据并合并。
Fork/Join 使用两个核心类完成以上操作:
ForkJoinTask 使用 ForkJoin 框架必须创建 ForkJoin 任务。它提供在任务中执行 fork() 和 join() 操作的机制。通常不需要直接继承 ForkJoinTask 类,而是继承其子类:
- RecursiveAction:用于没有返回结果的任务。
- RecursiveTask:用于有返回结果的任务。
ForkJoinPool ForkJoinTask 需要通过 ForkJoinPool 来执行。任务分割出的子任务会添加到当前工作线程维护的双端队列头部。当一个工作线程的队列为空时,它会随机从其他工作线程的队列尾部获取一个任务。
ForkJoinPool 池与工作窃取 ForkJoinPool 是一个存放任务的池子。它与 ExecutorService 的区别主要在于使用了'工作窃取'算法:一个大任务被划分成无数个小任务分配到不同队列,干活快的线程在完成自己队列的任务后,会从隔壁队列(通常是尾部)拿去任务执行,从而平衡负载。
测试代码
以下示例演示 RecursiveTask 实现求和逻辑。
package com.example.concurrent;
import java.util.concurrent.RecursiveTask;
public class ForkJoinUtil extends RecursiveTask<Integer> {
private final static int threshold = 3;
private final int start;
private final int end;
public ForkJoinUtil(int start, int end) {
this.start = start;
this.end = end;
}
@Override
Integer {
(end - start <= threshold) {
;
( start; i <= end; i++) {
sum += i;
}
sum;
} {
(start + end) / ;
(start, middle);
(middle + , end);
left.fork();
right.compute();
left.join();
leftResult + rightResult;
}
}
}


