parallelStream()仅在数据量≥10万、单元素处理≥1ms、操作无状态、数据源为ArrayList/数组时才真正提速;误用forEach修改共享集合会导致线程不安全,应改用collect;优先用parallelStream()而非stream().parallel(),必要时自定义ForkJoinPool隔离线程池。

直接调用 parallelStream() 就能开启并行流,但**开了不等于快**——它只在数据量大、单次处理重、结构合适时才真正提速;盲目使用反而因线程开销拖慢程序。
什么情况下 parallelStream 才真有效
并行流不是银弹,需同时满足这几个条件:
- 数据量够大:ArrayList 或数组 ≥ 10 万条;几千条的小集合基本不划算
- 单元素处理够重:每个元素操作耗时 ≥ 1ms(比如 JSON 解析、正则匹配、加密计算);纯数学运算或简单判断通常不够
- 操作无状态:filter、map、reduce 安全;sorted、distinct、limit 等有状态操作会削弱并行效率
- 数据源友好:优先用 ArrayList、数组;避开 LinkedList、Stream.generate()、自定义 Iterator(它们分割低效,甚至比串行还慢)
千万别在 forEach 里写共享集合
这是最常见也最危险的错误:
❌ 错误写法(非线程安全,可能丢数据、抛 ConcurrentModificationException):
立即学习“Java免费学习笔记(深入)”;
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
numbers.parallelStream()
.filter(n -> n % 2 == 0)
.forEach(result::add); // 危险!多个线程并发修改同一 ArrayList
✅ 正确做法:交给流自己聚合,用 collect 或 Java 16+ 的 toList():
.filter(n -> n % 2 == 0)
.map(n -> n * 2)
.collect(Collectors.toList()); // ✅ 线程安全,自动合并
// 或 Java 16+:
// .toList();
parallelStream() 和 stream().parallel() 怎么选
二者最终都走 ForkJoinPool.commonPool(),但语义和可维护性不同:
list.parallelStream()-
list.stream().parallel():适合已有流对象需动态切换场景,但链式调用中容易被忽略(比如stream().filter().parallel().map()),调试和阅读成本高
一旦调用 parallel(),后续所有中间和终止操作都会并行执行,无法中途切回串行。
进阶:自定义线程池避免干扰主线程
默认共用 ForkJoinPool.commonPool(),如果业务中有其他并行任务或 IO 阻塞操作,可能互相拖慢。这时建议隔离:
- 用系统属性全局调整(简单但不隔离):
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "8"); - 更推荐:创建专属
ForkJoinPool,把并行流提交进去执行:
List<String> result = customPool.submit(() ->
dataList.parallelStream()
.filter(s -> s.length() > 5)
.map(String::toUpperCase)
.collect(Collectors.toList())
).join();
对 IO 密集型任务,可适当提高并行度(如 CPU 核数 × 2);计算密集型任务一般设为核数 + 1 即可。


















