为什么要在 invokeAll 方法之后调用 join 呢?

Why should we call join after invokeAll method?

我正在尝试了解 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 文档,invokeAll() 将任务提交到池中,returns 结果为 well.Hence 不需要单独的 join()。有人可以解释为什么在这种情况下需要单独的连接吗?

在您的示例中,您使用的是 RecursiveTask<Integer> 所以你期望 return 来自 compute() 方法的值。

让我们看看invokAll(t1,t12)签名。

static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2)

所以 invokeAll() 没有 return 值。 根据文档:

Forks the given tasks, returning when isDone holds for each task or an (unchecked) exception is encountered, in which case the exception is rethrown.

所以:

return subTask1.join() + subTask2.join(); 是您示例的关键。 两个任务在每个任务完成后合并,将结果递归传递给下一次调用 compute() 方法。

task.join()

Returns the result of the computation when it is done.

根据 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.

因此,当任务完成后,join 会帮助您获取计算值,稍后您将把这些值加在一起。

return subTask1.join() + subTask2.join();