本文共 2563 字,大约阅读时间需要 8 分钟。
在Java 7中引入了一种新的线程池——ForkJoinPool。它既是Executor也是ExecutorService,同时采用无限队列来管理需要执行的任务,线程数量通过构造函数指定,默认以CPU核数为准。
ForkJoinPool主要用于带有明显分治关系的任务,典型用途是快速排序等Divide-and-Conquer算法。其核心思想是使用少量线程高效处理大量任务。通过将大任务拆分成多个小任务,分布到多个处理器核心上并行执行,最终合并结果。在本地排序中,任务会分割到500万数据左右时开始递归拆分,当数据量低于10时采用插入排序。
关键点:
其内部使用ownable线程池和任务队列,实现基于分治算法的并行计算,例如分解一个大的排序任务到多个子任务,然后合并各子任务的结果。在 tours成 losses和Consolidate阶段中,ForkJoinPool以优化资源利用率著称。
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(); }}
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成为Java程序针对具有复杂分治关系的任务高效并行执行的理想选择。
转载地址:http://kjjez.baihongyu.com/