批量任务用 supplyAsync 没传线程池,八核机器上只有 7 个线程在跑,几百个任务排成一队,耗时比串行还长。日志里能对上时间点,这种反而好排。
默认走 ForkJoinPool.commonPool,并行度是核数减一,还被整个 JVM 的并行流一起共用。这一点先确认清楚,后面就不用反复试。
CompletableFuture.supplyAsync(() -> load(id), bizPool); # commonPool 并行度 = 核数 - 1
围绕「commonPool 并行度」排查时,命令行跑一遍比在面板里点十次有用,面板会替你做掉不少隐式操作。先做最小复现,能稳定跑出来的问题,排查成本会低一个数量级。
别只看报错的最后一行,往上看几行,真正的起因通常在上面。同类问题如果隔一段时间又出现,多半是某个定时任务或重启流程把改动冲掉了。
把这次用到的命令存进笔记,比记住结论有用,换个环境还能照着走。
处理上按这个顺序:第二个参数显式传业务线程池;IO 任务按阻塞系数放大线程数;避免和 parallelStream 混用同一个池。
结果对不对很好判断,批量任务线程数按预期上去,总耗时降到原来的三分之一。
