Why should we call join after invokeAll method?

家住魔仙堡 提交于 2020-06-26 07:05:20

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!