1. 出现的原因
    • 线程池的缺点
      • 无法对大任务进行拆分,对于某个任务只能由单线程执行
      • 工作线程从队列中获取任务时存在竞争情况
    • ForkJoinPool就可以解决这些缺点
    1. 分治算法与Fork/Join模式
    • 在并发计算中,Fork/Join模式往往用于对大任务的并行计算,它通过递归的方式对任务不断地拆解,再将结果进行合并
    • 本质是分治算法(Divide-and-Conquer) 的应用
    • 分子算法
      • 分解:将要解决的问题划分成若干规模较小的同类问题;
      • 求解:当子问题划分得足够小时,用较简单的方法解决;
      • 合并:按原问题的要求,将子问题的解逐层合并构成原问题的解。

    image.png

    • 实例 ```java public class TheKingRecursiveSumTask extends RecursiveTask { private static final AtomicInteger taskCount = new AtomicInteger(); private final int sumBegin; private final int sumEnd; /**

      • 任务拆分阈值,当任务尺寸大于该值时,进行拆分 */ private final int threshold;

        public TheKingRecursiveSumTask(int sumBegin, int sumEnd, int threshold) { this.sumBegin = sumBegin; this.sumEnd = sumEnd; this.threshold = threshold; }

        @Override protected Long compute() { if ((sumEnd - sumBegin) > threshold) {

        1. // 两个数之间的差值大于阈值,拆分任务
        2. TheKingRecursiveSumTask subTask1 = new TheKingRecursiveSumTask(sumBegin, (sumBegin + sumEnd) / 2, threshold);
        3. TheKingRecursiveSumTask subTask2 = new TheKingRecursiveSumTask((sumBegin + sumEnd) / 2, sumEnd, threshold);
        4. subTask1.fork();
        5. subTask2.fork();
        6. taskCount.incrementAndGet();
        7. return subTask1.join() + subTask2.join();

        } // 直接执行结果 long result = 0L; for (int i = sumBegin; i < sumEnd; i++) {

         result += i;
        

        } return result; }

        public static AtomicInteger getTaskCount() { return taskCount; } }

    ```

    1. ForkJoinPool设计与源码分析

      描述

    ForkJoinPool是Fork/Join模型的实现,ForkJoinPool允许其他线程向它提交任务,并根据设定将这些任务拆分为粒度更细的子任务,这些子任务将由ForkJoinPool内部的工作线程来并行执行,并且工作线程之间可以窃取彼此之间的任务

    ForkJoinPool设计

    • 在接口实现和继承关系上,ForkJoinPool和ThreadPoolExecutor类似,都实现了Executor和ExecutorService接口,并继承了AbstractExecutorService抽类
    • ForkJoinPool主要有两种任务类型
      • RecursiveAction
      • RecursiveTask

    image.png

    • 四个核心参数
      • 并行数(int parallelism):决定工作线程的数量
      • 工作线程的创建(ForkJoinWorkerThreadFactory factory):创建线程时,会通过factory来创建
      • 异常处理(UncaughtExceptionHandler handler):指定异常处理器,当任务在运行中出错时,将由设定的处理器处理
      • 模式指定(boolean asyncMode):asyncMode ? FIFO_QUEUE : LIFO_QUEUE. 当asyncMode为true时,将使用先进先出队列,而为false时则使用后进先出的模式
    • 构造函数
      • 默认无参构造:ForkJoinPool将根据当前处理器数量来设置并行数量,并使用默认的线程构造工厂(不推荐)
      • 通过并行数构造:指定并行数量,以更有效地平衡处理器数量和负载。建议在设置时,并行级别应低于当前处理器的数量
      • 自定义全部参数构造:建议你使用这种构造方式


    1. 总结
    • 优点:
      • 任务切分:将大的任务分割成更小粒度的小任务,让更多的线程参与执行;
      • 任务窃取:通过任务窃取,充分地利用空闲线程,并减少竞争。
    • 适用范围:
      • 纯函数计算类型