能否用Java Stream对ArrayList元素并行调用计算方法并将结果存入HashMap
Java Stream并行计算月度营收需求实现方案
结论
完全可以通过Java并行流实现该需求,理论上50个任务的总耗时可以从原来的250分钟左右降低到和你机器核心数匹配的水平,比如8核心的场景下可以降到30分钟左右,优化效果非常明显。
优化后代码
import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.stream.Collectors; public HashMap<String, BigDecimal> calculateRevenueForAllMonths() { ArrayList<String> sMonths = new ArrayList<String>(); // sMonths = 存储50个月份的列表 // 并行流计算,直接收集为HashMap return sMonths.parallelStream() .collect(Collectors.toMap( month -> month, this::calculateRevenue, // 冲突处理逻辑,正常无重复月份,直接返回前者即可 (oldVal, newVal) -> oldVal, HashMap::new )); } public BigDecimal calculateRevenue(String mnth) { BigDecimal businessValue = BigDecimal.ZERO; // 原有计算逻辑保持不变 // 执行计算操作 // 将对应月份的营收结果存入BigDecimal类型变量 return businessValue; }
注意事项
- 要保证
calculateRevenue方法是线程安全的,方法内部不要使用非线程安全的共享可变变量,也不要修改外部公共变量,否则并行计算会出现数据异常。 - 并行流默认使用公共的ForkJoinPool,如果你业务中还有其他并行任务在运行,或者
calculateRevenue方法存在大量IO等待,建议自定义线程池来执行并行任务,避免公共池资源被占用导致优化效果打折扣,自定义池示例如下:
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ExecutionException; // 自定义10个线程的ForkJoinPool,可根据实际机器配置调整线程数 ForkJoinPool customPool = new ForkJoinPool(10); try { return customPool.submit(() -> sMonths.parallelStream().collect(Collectors.toMap( month -> month, this::calculateRevenue, (oldVal, newVal) -> oldVal, HashMap::new )) ).get(); } catch (InterruptedException | ExecutionException e) { // 自行补充异常处理逻辑 throw new RuntimeException("并行计算营收失败", e); } finally { customPool.shutdown(); }
- 你提供的原有代码存在笔误:循环中使用的
monthlyVR变量并未声明,实际应为提前创建的monthlyRevenue变量,流实现的代码已经修正了该问题。
内容的提问来源于stack exchange,提问作者Swetha Vani
相关产品推荐
相关产品推荐

