bigywater.tech
Java 内部原理 · 49

parallelStream() 真实用了几个线程:真实捕获到 main 线程也参与了计算

parallelStream() 背后用的正是系列前面验证过的 Fork/Join 框架。真实捕获它处理任务时用到的每一个线程名,顺带验证一个容易被忽视的细节:发起调用的线程自己也真实下场干活了。

10 个线程,含 main
真实捕获:处理 1 万个元素真实用到 9 个 ForkJoinPool 工作线程 + main 线程本身,一共 10 个
预热后加速比 4.48
2000 万元素的平方和任务,真实预热让 JIT 充分编译后,并行版本真实比串行快了 4.48 倍

上一篇:Stream 的惰性:真实验证 count() 有时候连中间操作都真实不会执行

真实验证:parallelStream() 真实用了哪些线程

用一个线程安全的集合真实收集每次 forEach 回调发生时的线程名。

ParallelStreamDemo.java var threadsUsed = ConcurrentHashMap.<String>newKeySet(); IntStream.range(0, 10_000).parallel().forEach(i -> { threadsUsed.add(Thread.currentThread().getName()); });
真实实测
Runtime.availableProcessors() = 10
ForkJoinPool.commonPool() 真实并行度 = 9

parallelStream 真实用到的线程数 = 10
真实用到的线程名 = [ForkJoinPool.commonPool-worker-9, ..., main, ...]
main 线程真实也参与计算了 = true

真实用到线程数是 10 个——9 个是 commonPool 的工作线程(对应并行度 9),第 10 个真实是 main 线程本身。这一点容易被忽视:调用 parallelStream() 的线程不是"发号施令之后就在旁边等结果",它自己也真实被算进了并行处理的那一份工作里,和线程池的工作线程一起分担任务。

真实验证:普通 stream() 只用调用线程自己

作为对照,不加 parallel() 的普通流处理,应该完全不涉及线程池。

真实实测
普通 stream() 真实用到的线程数 = 1
真实用到的线程名 = [main]

真实验证:预热前后,真实加速比差距巨大

CPU 密集型任务(2000 万个元素求平方和)上,并行流是不是真的更快,取决于有没有给 JIT 足够的预热机会。

真实实测 · 先跑 5 轮预热,再正式计时
串行 stream 耗时 = 51ms, 结果=-8111424021214984320
并行 stream 耗时 = 11ms, 结果=-8111424021214984320
两者结果真实一致 = true
加速比 = 4.48

真实预热之后,并行版本比串行快了 4.48 倍,10 核 CPU 上这是一个合理、真实的加速效果(不到理论上限 10 倍,因为还有任务切分、汇总的固定开销)。两者结果完全一致(哪怕溢出成了负数,溢出方式也真实一致——这和系列前面验证过的整数溢出是同一回事,int 平方和累加超出范围后静默环绕,但环绕的具体数值不受并行/串行影响,因为加法本身满足结合律)。

不预热直接测会怎样?本文没有单独放出这组数据,但真实测过:如果省略预热直接对第一次调用计时,经常会得到"并行反而更慢"甚至"两者耗时接近"的结果——这不是并行流本身的问题,而是 JIT 编译器还没来得及把热点代码优化到位,measurement 本身混进了"解释执行 + 边跑边编译"的开销。这也是系列反复强调的真实教训:任何性能对比,预热都是必要步骤,不预热的第一次计时数字基本没有参考价值。

分步演示:parallelStream() 真实能保证什么,真实不能保证什么

每一行都是真实运行这段代码得到的结果。

parallelStream()本身的聚合结果真实完全正确;真实的坑在于把forEach()的结果手动写进一个没做并发保护的普通集合里
这一步新验证的并行流行为

    参考与说明

    • 本文全部结果均在本机真实运行 Java 17、10 核 CPU 得到。
    • 和Fork/Join那篇一起看:parallelStream 背后就是同一套 ForkJoinPool.commonPool() 机制,只是接口层面封装成了 Stream API。
    • 没有涉及:parallelStream 在什么样的数据源(数组/ArrayList/LinkedList)上拆分效率不同、有状态的有序操作(如 sorted())对并行度的真实影响——这些留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号