1.什么是Fork/join框架
用于执行并行任务,是把一个大任务分成若干个小任务执行(fork),最终汇总每个小任务结果后得到大任务结果(join)的框架。
适用于CPU密集型运算,默认会创建与CPU核心数相等的线程池。
2.工作窃取算法
2.1 介绍
工作窃取(work-stealing)算法是指某个线程从其他队列里窃取任务来执行。
干完活的线程会从其他线程的双端队列尾部窃取任务来完成,而被窃取的线程则是从双端队列的头部取出任务。
2.2 优点
充分利用线程进行并行计算,减少了线程间的竞争。
2.3 缺点
在某些情况下还是存在竞争,比如双端队列中只有一个任务时。并且该算法会消耗了更多的系统资源,比如创建多个线程和多个双端队列。
3.使用
分割的子任务分别放在双端队列里,然后几个启动线程分别从双端队列里获取任务执行。子任务执行完的结果都统一放在一个队列里,启动一个线程从队列里拿数据,然后合并这些数据。
①ForkJoinTask:我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务中执行fork()和join()操作的机制。通常情况下,我们不需要直接继承ForkJoinTask类,只需要继承它的子类,Fork/Join框架提供了以下两个子类。
-RecursiveAction:用于没有返回结果的任务。
-RecursiveTask:用于有返回结果的任务。
②ForkJoinPool:ForkJoinTask需要通过ForkJoinPool来执行。
使用示例代码如下
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
public class CountTask extends RecursiveTask<Integer> {
private static final int THRESHOLD=2;
private int start;
private int end;
public CountTask(int start,int end){
this.start=start;
this.end=end;
}
@Override
protected Integer compute() {
int sum=0;
boolean canCompute=(end-start)<=THRESHOLD;
if(canCompute){
for(int i=start;i<=end;i++){
sum+=i;
}
}
else{
int middle=(start+end)/2;
CountTask leftTask=new CountTask(start,middle);
CountTask rightTask=new CountTask(middle+1,end);
leftTask.fork();
rightTask.fork();
int leftResult=leftTask.join();
int rightResult=rightTask.join();
sum=leftResult+rightResult;
}
return sum;
}
public static void main(String[] args) {
ForkJoinPool pool=new ForkJoinPool();
CountTask task=new CountTask(2,4);
Future<Integer> result=pool.submit(task);
try{
System.out.println(result.get());
}
catch (Exception e){
}
}
}
输出