分支/合并框架Fork/Join是Java 7中引入的一个并行计算框架,主要用于解决一些大规模的并行问题,本质是分治思想解决问题,可以有效地利用多核CPU提高程序的性能。
Fork/Join框架的核心就是ForkJoinPool、ForkJoinTask和RecursiveTask。
ForkJoinPool:线程池
ForkJoinPool是Fork/Join框架的核心类,它管理了一个线程池,可以创建和调度ForkJoinTask任务。通过构造函数创建ForkJoinPool对象时,可以指定线程池的大小、线程池的名称等属性。
ForkJoinTask:任务
ForkJoinTask是一个抽象类,它定义了Fork/Join任务的基本行为。用户可以继承ForkJoinTask类,实现自己的任务。ForkJoinTask有两个重要的子类:RecursiveAction和RecursiveTask。
RecursiveAction:没有返回值的任务
RecursiveAction是ForkJoinTask的子类,表示没有返回值的任务。如果需要执行一个没有返回值的任务,可以继承RecursiveAction类,并重写compute()方法。在compute()方法中,可以将任务分解成更小的任务,并将这些任务提交到ForkJoinPool中,从而实现并行计算。
RecursiveTask:有返回值的任务
RecursiveTask是ForkJoinTask的子类,表示有返回值的任务。如果需要执行一个有返回值的任务,可以继承RecursiveTask类,并重写compute()方法。在compute()方法中,可以将任务分解成更小的任务,并将这些任务提交到ForkJoinPool中。当所有任务执行完成后,使用get()方法可以获取所有子任务的结果,并将这些结果合并成一个结果。
下面是一个示例,演示如何使用Fork/Join框架对一个大数组进行并行计算求和。
import java.util.concurrent.RecursiveTask;
public class SumTask extends RecursiveTask<Long> {
private static final int THRESHOLD = 10000;
private int[] arr;
private int start;
private int end;
public SumTask(int[] arr, int start, int end) {
this.arr = arr;
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if (end - start <= THRESHOLD) {
long sum = 0;
for (int i = start; i < end; i++) {
sum += arr[i];
}
return sum;
} else {
int mid = (start + end) / 2;
SumTask left = new SumTask(arr, start, mid);
SumTask right = new SumTask(arr, mid, end);
left.fork();
right.fork();
return left.join() + right.join();
}
}
public static void main(String[] args) {
int[] arr = new int[1000000];
for (int i = 0; i < arr.length; i++) {
arr[i] = i + 1;
}
SumTask task = new SumTask(arr, 0, arr.length);
long result = task.compute();
System.out.println(result);
}
}
这个示例中,我们创建了一个SumTask类,它继承了RecursiveTask类。SumTask的任务是计算一个大数组的元素之和。在compute方法中,如果待计算的数组大小小于等于阈值THRESHOLD,我们就直接计算这个数组的元素之和;否则,将这个数组分成两个子数组,分别构造两个SumTask对象进行递归计算,最后将两个子任务的计算结果加起来返回。在递归计算的过程中,我们使用了fork和join方法,将任务分裂成子任务,提交给线程池进行并行计算。
在main方法中,我们创建了一个长度为1000000的数组,并构造了一个SumTask对象对其进行计算。最终的结果会被打印输出。注意到我们没有显式地创建线程池,而是使用了ForkJoinPool的默认线程池,它会根据CPU核心数自动创建适当数量的线程,这样可以充分利用多核CPU的性能。