You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化Java中平方根与立方根差值累加计算的性能?

优化计算密集型分治任务:用ForkJoinPool和并行流提速你的数值累加

嘿,你的思路完全没错!ForkJoinPool和并行流确实能帮你进一步榨干多核CPU的性能,尤其是这种计算密集型的分治任务。先给你指个小细节:你代码里的calculatorService构造函数写成了SqrtSummer,这是个笔误,得修正一下。接下来我给你具体演示两种优化方案:


一、用ForkJoinPool实现精细化分治

ForkJoinPool天生就是为分治任务设计的,它会自动帮你拆分任务、调度线程,比固定线程池更灵活,能减少任务调度的开销。你需要实现一个RecursiveTask来定义你的计算单元:

import java.text.DecimalFormat;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

public class ForkJoinCalculator {
    private static final int TARGET_NUM = Integer.MAX_VALUE;
    // 拆分阈值:当区间大小小于这个值时,直接计算,避免过度拆分带来的开销
    private static final int SPLIT_THRESHOLD = 100000;

    public static void main(String[] args) {
        DecimalFormat df2 = new DecimalFormat(".##");
        long startTime = System.currentTimeMillis();

        ForkJoinPool forkJoinPool = new ForkJoinPool();
        // 提交根任务:计算0到TARGET_NUM的总和
        Double total = forkJoinPool.invoke(new SqrtCbrtSumTask(0, TARGET_NUM));

        System.out.println("Result= " + df2.format(total) + "\nTime passed= " + ((System.currentTimeMillis() - startTime)/1000f));
        forkJoinPool.shutdown();
    }

    static class SqrtCbrtSumTask extends RecursiveTask<Double> {
        private final int start;
        private final int end;

        public SqrtCbrtSumTask(int start, int end) {
            this.start = start;
            this.end = end;
        }

        @Override
        protected Double compute() {
            // 如果区间足够小,直接计算
            if (end - start <= SPLIT_THRESHOLD) {
                double sum = 0;
                for (int i = start; i <= end; i++) {
                    sum += Math.sqrt(i) - Math.cbrt(i);
                }
                return sum;
            } else {
                // 拆分任务:分成左右两个子任务
                int mid = (start + end) / 2;
                SqrtCbrtSumTask leftTask = new SqrtCbrtSumTask(start, mid);
                SqrtCbrtSumTask rightTask = new SqrtCbrtSumTask(mid + 1, end);
                // 执行子任务
                invokeAll(leftTask, rightTask);
                // 合并结果
                return leftTask.join() + rightTask.join();
            }
        }
    }
}

关键点说明:

  • 拆分阈值:我设了100000,你可以根据自己的CPU核心数调整——太小会导致任务调度过多,太大则无法充分利用并行能力。
  • ForkJoinPool会自动管理线程,不需要你手动拆分区间给固定数量的线程,它会根据系统负载动态调整任务分配。

二、用并行流实现极简版本

如果你不想写复杂的ForkJoin任务,Java 8+的并行流能以极简的代码实现并行计算,底层其实也是用ForkJoinPool:

import java.text.DecimalFormat;
import java.util.stream.IntStream;

public class ParallelStreamCalculator {
    private static final int TARGET_NUM = Integer.MAX_VALUE;

    public static void main(String[] args) {
        DecimalFormat df2 = new DecimalFormat(".##");
        long startTime = System.currentTimeMillis();

        // 用并行流直接计算总和
        double total = IntStream.rangeClosed(0, TARGET_NUM)
                .parallel()
                .mapToDouble(i -> Math.sqrt(i) - Math.cbrt(i))
                .sum();

        System.out.println("Result= " + df2.format(total) + "\nTime passed= " + ((System.currentTimeMillis() - startTime)/1000f));
    }
}

进阶优化:自定义并行流的线程池

默认的并行流用的是公共ForkJoinPool,如果你想控制线程数量,可以自定义线程池:

import java.text.DecimalFormat;
import java.util.concurrent.ForkJoinPool;
import java.util.stream.IntStream;

public class CustomPoolParallelStream {
    private static final int TARGET_NUM = Integer.MAX_VALUE;
    private static final int THREAD_COUNT = 8;

    public static void main(String[] args) {
        DecimalFormat df2 = new DecimalFormat(".##");
        long startTime = System.currentTimeMillis();

        ForkJoinPool customPool = new ForkJoinPool(THREAD_COUNT);
        double total = customPool.submit(() -> 
            IntStream.rangeClosed(0, TARGET_NUM)
                    .parallel()
                    .mapToDouble(i -> Math.sqrt(i) - Math.cbrt(i))
                    .sum()
        ).join();

        System.out.println("Result= " + df2.format(total) + "\nTime passed= " + ((System.currentTimeMillis() - startTime)/1000f));
        customPool.shutdown();
    }
}

为什么这两种方案比你原来的FixedThreadPool更快?

  1. 任务调度更高效:ForkJoinPool用的是工作窃取算法,空闲线程会主动从忙碌线程的任务队列里拿任务执行,减少线程 idle 的时间。
  2. 动态任务拆分:不需要你手动拆分固定区间给线程,ForkJoin会根据实际计算情况拆分任务,让每个线程的负载更均衡。
  3. 并行流的极简封装:底层优化了很多细节,比如避免了Future的手动等待和汇总,代码更简洁且性能优异。

你可以自己测试一下这几种方案的耗时,应该会比你现有的8线程版本更快~

内容的提问来源于stack exchange,提问作者Mert Serimer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:32:10