问题
I am trying to learn about the ForkJoinPool framework and came across the below example:
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;
}
}
Main :
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;
}
}
According to the Java Docs,invokeAll() submits the tasks to the pool and returns the results as well.Hence no need for a separate join(). can someone please explain why a separate join is needed in this case?
回答1:
in your example, you are using RecursiveTask<Integer>
so you are expecting to return a value from compute()
method.
let's look at invokAll(t1,t12)
signature.
static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2)
so invokeAll()
doesn't have return a value.
according to the documentation :
Forks the given tasks, returning when isDone holds for each task or an (unchecked) exception is encountered, in which case the exception is rethrown.
So:
return subTask1.join() + subTask2.join();
is the key for your example.
both tasks are merged after each complete the task passing the result recursivly to the next call of compute()
method.
task.join()
Returns the result of the computation when it is done.
回答2:
As per javadoc, join
Returns the result of the computation when it is done. This method differs from get() in that abnormal completion results in RuntimeException or Error, not ExecutionException, and that interrupts of the calling thread do not cause the method to abruptly return by throwing InterruptedException.
So, when task is done, join
helps you to get the computed value, which you are adding later together.
return subTask1.join() + subTask2.join();
来源:https://stackoverflow.com/questions/48634809/why-should-we-call-join-after-invokeall-method