ForkJoinPool线程池
发布日期:2021-05-20 12:06:35 浏览次数:12 分类:精选文章

本文共 2563 字,大约阅读时间需要 8 分钟。

在Java 7中引入了一种新的线程池——ForkJoinPool。它既是Executor也是ExecutorService,同时采用无限队列来管理需要执行的任务,线程数量通过构造函数指定,默认以CPU核数为准。

ForkJoinPool主要用于带有明显分治关系的任务,典型用途是快速排序等Divide-and-Conquer算法。其核心思想是使用少量线程高效处理大量任务。通过将大任务拆分成多个小任务,分布到多个处理器核心上并行执行,最终合并结果。在本地排序中,任务会分割到500万数据左右时开始递归拆分,当数据量低于10时采用插入排序。

关键点

  • 任何一个任务的执行都必须等待其所有子任务完成。
  • ForkJoinPool实现对任务顺序的严格控制,无需像ThreadPoolExecutor那样依赖线程完成子任务的执行。
  • 其内部使用ownable线程池和任务队列,实现基于分治算法的并行计算,例如分解一个大的排序任务到多个子任务,然后合并各子任务的结果。在 tours成 losses和Consolidate阶段中,ForkJoinPool以优化资源利用率著称。

    与ThreadPoolExecutor的区别

    • ForkJoinPool允许用少量线程处理大量具有父子关系的任务,而ThreadPoolExecutor的线程无法高效处理此类任务。这是因为ForkJoinPool支持线程创建新的任务并挂起当前任务,线程能够访问和处理队列中的任务。

    注意事项

    • ForkJoinPool在处理大量任务时会创建大量子任务,导致GC压力增大。
    • 需要注意设置合理的任务分割阈值,以避免过度拆分导致性能瓶颈。

    代码示例,以下是两个使用ForkJoinPool进行数据处理的应用程序:

    ForkJoinPoolAction demo

    package chap07.ForkJoinDemo.ForkJoin;import java.util.concurrent.ForkJoinPool;import java.util.concurrent.TimeUnit;public class ForkJoinPoolAction {    // ForkJoinPool的优势在于,可以充分利用多CPU、多核CPU的优势,将一个任务拆分成多个"小任务",将这些小任务分配到多个处理器核心上并行执行。    // 当所有Subtasks完成后,再将结果合并到一起。    public static void main(String[] args) throws Exception {        // 需要打印1到300的数字。将一个大任务拆分成多个小任务并交给ForkJoinPool执行。        PrintTask task = new PrintTask(0, 3000);        ForkJoinPool pool = new ForkJoinPool();        pool.submit(task);        pool.awaitTermination(2, TimeUnit.SECONDS);        pool.shutdown();    }}

    PrintTask 类

    package chap07.ForkJoinDemo.ForkJoin;import java.util.concurrent.RecursiveAction;public class PrintTask extends RecursiveAction {    private static final int THRESPولد = 50; // 最多只能打印50个数字    private int start;    private int end;    @Override    protected void compute() {        if (end - start < THRESPOtherwise) {            for (int i = start; i < end; i++) {                System.out.println(Thread.currentThread().getName() + "的i值:" + i);            }        } else {            int mid = (start + end) / 2;            PrintTask leftTask = new PrintTask(start, mid);            PrintTask rightTask = new PrintTask(mid, end);            leftTask.fork();            rightTask.fork();        }    }    public PrintTask(int start, int end) {        this.start = start;        this.end = end;    }    public int getStart() {        return start;    }}

    性能对比

    使用ForkJoinPool处理具有明显父子关系的任务时,能显著降低线程数需求。例如,使用4个线程即可处理超过2000万个任务,而ThreadPoolExecutor需要逐一处理。这种精简化的线程管理使ForkJoinPool在并行处理大量任务时表现更优。

    户交流总结

  • ForkJoinPool通过利用分治算法和少量线程高效处理大量任务,打破了传统线程池对线程数量的等比例需求。
  • ForkJoinPool内部管理任务队列,确保任务的时间和空间上的正确执行顺序。
  • ForkJoinPool与ThreadPoolExecutor相比,特别适用于需要合并子任务结果的任务场景,能够显著优化资源利用率。
  • 通过这些特性,ForkJoinPool成为Java程序针对具有复杂分治关系的任务高效并行执行的理想选择。

    上一篇:JDK8-Optional类避免NPE
    下一篇:JDK8新特性并行流-ParallelStream

    发表评论

    最新留言

    逛到本站,mark一下
    [***.202.152.39]2025年05月05日 07时48分34秒

    关于作者

        喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
    -- 愿君每日到此一游!

    推荐文章