我正在尝试了解ForkJoinPool框架,并遇到了以下示例:
public class ArrayCounter extends RecursiveTask<Integer> {
int[] array;
int threshold = 100_000;
int start;
int end;
public ArrayCounter(int[] array, int start, int end) {
this.array = array;
this.start = start;
this.end = end;
}
protected Integer compute() {
if (end - start < threshold) {
return computeDirectly();
} else {
int middle = (end + start) / 2;
ArrayCounter subTask1 = new ArrayCounter(array, start, middle);
ArrayCounter subTask2 = new ArrayCounter(array, middle, end);
invokeAll(subTask1, subTask2);
return subTask1.join() + subTask2.join();
}
}
protected Integer computeDirectly() {
Integer count = 0;
for (int i = start; i < end; i++) {
if (array[i] % 2 == 0) {
count++;
}
}
return count;
}
}
主要:
public class ForkJoinRecursiveTaskTest
{
static final int SIZE = 10_000_000;
static int[] array = randomArray();
public static void main(String[] args) {
ArrayCounter mainTask = new ArrayCounter(array, 0, SIZE);
ForkJoinPool pool = new ForkJoinPool();
Integer evenNumberCount = pool.invoke(mainTask);
System.out.println("Number of even numbers: " + evenNumberCount);
}
static int[] randomArray() {
int[] array = new int[SIZE];
Random random = new Random();
for (int i = 0; i < SIZE; i++) {
array[i] = random.nextInt(100);
}
return array;
}
}
根据Java Docs,invokeAll()将任务提交给池并返回结果。因此不需要单独的join()。请问有人可以解释为什么在这种情况下需要单独加入?
答案 0 :(得分:3)
根据javadoc,join
完成后计算的 结果 。这种方法 与get()的不同之处在于异常完成导致 RuntimeException或Error,而不是ExecutionException,并且中断 调用线程不会导致方法突然返回 抛出InterruptedException。
因此,当任务完成后,join
会帮助您获取计算出的值,稍后您将一起添加。
return subTask1.join() + subTask2.join();
答案 1 :(得分:1)
RecursiveTask<Integer>
所以你期望从compute()
方法返回一个值。
让我们看一下invokAll(t1,t12)
签名。
static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2)
所以invokeAll()
没有返回值。
根据文件:
分叉给定的任务,当isDone为每个任务保留或者遇到(未经检查的)异常时返回,在这种情况下重新抛出异常。
<强>所以:强>
return subTask1.join() + subTask2.join();
是您示例的关键。
两个任务在每次完成后合并,任务将结果递归地传递给下一个compute()
方法调用。
task.join()
完成后返回计算结果。