【问题标题】:Why should we call join after invokeAll method?为什么我们要在 invokeAll 方法之后调用 join?
【发布时间】:2018-02-06 03:02:18
【问题描述】:

我正在尝试了解 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()。有人可以解释一下为什么在这种情况下需要单独加入吗?

【问题讨论】:

    标签: java multithreading concurrency java.util.concurrent invokeall


    【解决方案1】:

    在您的示例中,您使用的是RecursiveTask&lt;Integer&gt; 所以你期望从compute() 方法返回一个值。

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

    static void invokeAll(ForkJoinTask&lt;?&gt; t1, ForkJoinTask&lt;?&gt; t2)

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

    分叉给定的任务,当每个任务的 isDone 成立或遇到(未经检查的)异常时返回,在这种情况下会重新抛出异常。

    所以:

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

    task.join()

    完成后返回计算结果。

    【讨论】:

      【解决方案2】:

      根据 javadoc,join

      返回完成后的计算结果。这种方法 与 get() 的不同之处在于异常完成导致 RuntimeException 或 Error,而不是 ExecutionException,并且会中断 调用线程不会导致方法突然返回 抛出 InterruptedException。

      因此,当任务完成时,join 会帮助您获取计算值,然后将其相加。

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

      【讨论】:

        猜你喜欢
        • 2020-09-06
        • 2013-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-29
        相关资源
        最近更新 更多