继承recursivetask是java实现有返回值分治并行计算的标准方式,需重写compute()方法:任务足够小时直接计算返回,否则拆分子任务fork/join后合并结果;泛型t表示返回类型,如long。

继承 RecursiveTask 是 Java 中实现有返回值的分治式并行计算的标准方式,核心在于重写 compute() 方法,并在任务足够小时直接计算返回结果,否则拆分为子任务、fork/join 执行后合并结果。
理解 RecursiveTask 的作用和泛型含义
RecursiveTask<t></t> 是 ForkJoinTask 的子类,专用于**有返回值**的递归并行任务。泛型参数 T 表示该任务执行完成后返回的数据类型,比如 Integer、Long 或自定义对象。
它与无返回值的 RecursiveAction 的关键区别在于:compute() 方法必须返回一个 T 类型的值,且框架会自动收集并传递这个结果给调用方(如 invoke() 或 join())。
继承 RecursiveTask 的基本步骤
以“并行计算数组整数和”为例,说明典型实现流程:
-
定义子类并指定返回类型:例如
class SumTask extends RecursiveTask<long></long> -
构造任务时传入待处理数据和划分边界:如数组引用、起始索引
lo、结束索引hi -
重写 compute() 方法:
- 设定阈值(如
hi - lo ),满足则循环累加并返回结果 - 不满足则拆成两个子任务(如
mid = (lo + hi) / 2),分别创建new SumTask(arr, lo, mid)和new SumTask(arr, mid, hi) - 调用
left.fork()异步执行左子任务,right.compute()同步执行右子任务(或都用fork()再join()) - 用
left.join() + right.join()合并结果并返回
- 设定阈值(如
-
提交任务到 ForkJoinPool:推荐使用公共池
ForkJoinPool.commonPool().invoke(task),或显式创建池
关键细节与常见注意事项
实际编码中容易忽略但影响正确性和性能的点:
- 避免共享可变状态:任务间不要共用数组元素的修改变量;若需中间结果,应在任务内部创建局部变量或不可变容器
- 拆分要均衡,避免深度过深或过浅:阈值太小导致任务过多、调度开销大;太大则并行度不足。通常根据数据规模和 CPU 核心数经验调整(如每任务处理 100–10000 个元素)
-
compute() 必须有明确返回值:即使某分支提前 return,所有执行路径都要返回合法的
T值,不能漏写 -
异常处理要主动捕获:子任务抛出的异常会被包装为
ForkJoinTask.ExecutionException,可在invoke()外层 try-catch,或在compute()内部处理
一个完整可运行的小例子
计算 long[1_000_000] 的和:
class SumTask extends RecursiveTask<long> {
private final long[] array;
private final int lo, hi;
private static final int THRESHOLD = 10_000;
<pre class="brush:java;toolbar:false;">SumTask(long[] array, int lo, int hi) {
this.array = array;
this.lo = lo;
this.hi = hi;
}
@Override
protected Long compute() {
if (hi - lo <= THRESHOLD) {
long sum = 0;
for (int i = lo; i < hi; i++) sum += array[i];
return sum;
}
int mid = (lo + hi) / 2;
SumTask left = new SumTask(array, lo, mid);
SumTask right = new SumTask(array, mid, hi);
left.fork(); // 异步执行左半
long rightSum = right.compute(); // 当前线程算右半
long leftSum = left.join(); // 等待左半完成
return leftSum + rightSum;
}
}
// 使用: long[] arr = new long[1_000_000]; Arrays.fill(arr, 1); Long result = ForkJoinPool.commonPool().invoke(new SumTask(arr, 0, arr.length)); System.out.println(result); // 输出 1000000
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











