什么是Fork/Join框架
Fork/Join框架是Java 7 引入的一个用于并行计算的框架,它基于“分而治之”的思想,特别适合处理可以递归分解的任务。
其本质是将一个大任务拆分成多个小任务(Fork),并行执行这些小任务,最后将各任务的结果合并(Join)得到最终结果。
由于线程池的优化,提交的任务和线程数量并不是⼀对⼀的关系。在绝大多数情况下,⼀个物理线程实际上是需要处理多个逻辑任务的,每个线程必然需要拥有⼀个任务队列。在实际执⾏过程中,可能遇到这么⼀种情况:线程A已经把⾃⼰的任务都执⾏完了,⽽线程B还有⼀堆任务等着处理,此时,线程A就会“帮助”线程B,从线程B的任务队列中拿⼀个任务过来处理
这就通过工作窃取算法(Work-Stealing) 提高CPU利用率:每个工作线程维护一个双端队列,完成自己队列中的任务后,可以从其他线程队列的尾部“窃取”任务执行,减少线程空闲时间。
使用示例
第一步:创建一个RecursiveTask的子类
该子类用于计算从start到end的累加和。
如果start到end的间隔小于THRESHOLD,则直接计算,如果大于THRESHOLD,则拆分任务。
class SumTask extends RecursiveTask<Long>{
private final long start;
private final long end;
private static final long THRESHOLD=10_000;
public SumTask(long start,long end){
this.start=start;
this.end=end;
}
@Override
protected Long compute() {
if(end-start<=this.THRESHOLD){
long sum=0;
for(long i=start;i<=end;i++){
sum+=i;
}
return sum;
}else{
long mid=(start+end)/2;
SumTask leftTask=new SumTask(start,mid);
SumTask rightTask=new SumTask(mid+1,end);
leftTask.fork();
rightTask.fork();
long leftResult=leftTask.join();
long rightResult=rightTask.join();
return leftResult+rightResult;
}
}
}
第二步:使用线程池执行任务
ForkJoinPool forkJoinPool=new ForkJoinPool();
SumTask task=new SumTask(1,100_0000);
Long result=forkJoinPool.invoke(task);
System.out.println(result);
ForkJoinTask类
ForkJoinTask是Java并发编程中Fork/Join框架的核心抽象类,它代表了一个可以并行执行和合并结果的任务。
它有两个子类:
RecursiveAction:用于没有返回值的任务(如并行排序、遍历)RecursiveTask<V>:用于有返回值的任务(如并行求和、查找)