在fork/join部分的Java并发教程中,"computeDirectly"函数是如何通过"invokeAll"执行的?

In Java concurrency tutorial in fork/join section, how is the "computeDirectly" function executed via "invokeAll"?

the fork/join chapter官方Java并发教程中,有以下部分示例代码。

我知道如果图像数组大小小于阈值 (100,000),则会直接计算 (computeDirectly)。否则它会分成两半,并创建和调用两个 ForkBlur 对象 (invokeAll)。我不明白的是 invokeAll 最终如何为这些片段执行 computeDirectly 函数。

对于大于阈值的数组,如何调用computeDirectly函数? (它被分成几部分。)

public class ForkBlur extends RecursiveAction {
   private int[] mSource;
   private int mStart;
   private int mLength;
   private int[] mDestination;

   // Processing window size; should be odd.
   private int mBlurWidth = 15;

   public ForkBlur(int[] src, int start, int length, int[] dst) {
      mSource = src;
      mStart = start;
      mLength = length;
      mDestination = dst;
   }

   protected void computeDirectly() {
      int sidePixels = (mBlurWidth - 1) / 2;
      for (int index = mStart; index < mStart + mLength; index++) {
         // Calculate average.
         float rt = 0, gt = 0, bt = 0;
         for (int mi = -sidePixels; mi <= sidePixels; mi++) {
            int mindex = Math.min(Math.max(mi + index, 0),
                                  mSource.length - 1);
            int pixel = mSource[mindex];
            rt += (float)((pixel & 0x00ff0000) >> 16)
                 / mBlurWidth;
            gt += (float)((pixel & 0x0000ff00) >>  8)
                 / mBlurWidth;
            bt += (float)((pixel & 0x000000ff) >>  0)
                 / mBlurWidth;
         }

         // Reassemble destination pixel.
         int dpixel = (0xff000000    ) |
               (((int)rt) << 16) |
               (((int)gt) <<  8) |
               (((int)bt) <<  0);
         mDestination[index] = dpixel;
      }
   }

  ...

而这个单独的部分称它为:

protected static int sThreshold = 100000;

protected void compute() {
   if (mLength < sThreshold) {
      computeDirectly();
      return;
   }

   int split = mLength / 2;

   invokeAll(new ForkBlur(mSource, mStart, split, mDestination),
           new ForkBlur(mSource, mStart + split, mLength - split,
                     mDestination));
}

这个

invokeAll(new ForkBlur(mSource, mStart, split, mDestination),
       new ForkBlur(mSource, mStart + split, mLength - split,
                 mDestination));

最终调用 ForkBlurcompute 方法,如果您将其拆分到足够小的阈值,将通过 [=15= 执行 computeDirectly ] 这里的条件

if (mLength < sThreshold) {
    computeDirectly();
    return;
}

所以一个大任务被拆分成两个(或更多)较小的任务,这些任务可能会再次拆分,然后再拆分,直到任务小到 运行。