本章简说一下ForkJoin
ForkJoin是Java7提供的原生多线程并行处理框架,其基本思想是将大人物分割成小任务,最后将小任务聚合起来得到结果。Fork/Join采用“工作窃取模式”,当执行新的任务时他可以将其拆分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随即线程中偷一个并把它加入自己的队列中
Fork就是把一个大任务切分为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果。比如计算1+2+。。+10000,可以分割成10个子任务,每个子任务分别对1000个数进行求和,最终汇总这10个子任务的结果
我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务中执行fork()和join的操作机制,通常我们不直接继承ForkjoinTask类,只需要直接继承其子类。
- 继承RecursiveAction,用于没有返回结果的任务;
- 继承RecursiveTask,用于有返回值的任务。
ForkJoinPool:task要通过ForkJoinPool来执行,分割的子任务也会添加到当前工作线程的双端队列中,进入队列的头部。当一个工作线程中没有任务时,会从其他工作线程的队列尾部获取一个任务。
下面看一个累加求和的例子:
import java.util.concurrent.*;
public class ForkJoinTest extends RecursiveTask<Integer> {
private static final int thresheld = 2;
private int start;
private int end;
public ForkJoinTest(int start, int end){
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
int sum = 0;
boolean flag = (end - start) <= thresheld;
//如果未执行的任务数量小于等于了线程数量,则表示未完成的任务很少了,可以直接进行计算
if(flag){
for(int i = start; i <= end; i++){
sum += i;
}
}else{ //如果未执行的任务数量大于等于了线程数量,则表示未完成的任务还有很多,使用ForkJoin
int middle = (start + end) / 2; //平均分配任务数量
ForkJoinTest forkJoinTest1 = new ForkJoinTest(start, middle); //执行前半部分的任务
ForkJoinTest forkJoinTest2 = new ForkJoinTest(middle + 1, end); //执行后半部分的任务
//开始执行子任务
forkJoinTest1.fork();
forkJoinTest2.fork();
//得到结果
int res1 = forkJoinTest1.join();
int res2 = forkJoinTest2.join();
sum = res1 + res2;
}
return sum;
}
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTest task = new ForkJoinTest(1, 1000);//计算1-100的和
Future<Integer> result = forkJoinPool.submit(task); //执行这个任务
try {
System.out.printf(result.get().toString());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
我比较喜欢把解释写在代码注释里,大家看代码哈
个人浅薄理解,欢迎补充