Java parallelStream并行流

目录

前言

parallelStream() 是 Java 8 Stream API 提供的 并行流(Parallel Stream)

它可以让:

  • 一个集合的处理逻辑
  • 自动使用多线程并行执行

而不是单线程。


一、最简单理解

普通 stream:

java 复制代码
list.stream()

是 单线程

例如:

java 复制代码
1个线程处理20万数据

parallelStream:

java 复制代码
list.parallelStream()

是 多线程并行处理

例如:

text 复制代码
8核CPU
可能8个线程同时处理

二、举个最简单例子

普通 stream :

java 复制代码
list.stream()
    .map(x -> doSomething(x))
    .collect(Collectors.toList());

执行过程:

text 复制代码
第1条
第2条
第3条
...

按顺序一个个执行。


parallelStream :

java 复制代码
list.parallelStream()
    .map(x -> doSomething(x))
    .collect(Collectors.toList());

执行过程:

text 复制代码
线程1 -> 第1万条
线程2 -> 第2万条
线程3 -> 第3万条
...

同时执行。


三、parallelStream底层是什么?

底层使用: ForkJoinPool

默认:

text 复制代码
CPU核心数 - 1

例如:

8核CPU:

text 复制代码
默认7个工作线程

四、parallelStream什么时候适合?

适合:CPU密集型任务

例如:

  • 大量计算
  • 加密
  • 哈希
  • 复杂规则计算
  • 图片处理
  • 金额计算
  • 风控计算

例如:

java 复制代码
list.parallelStream()
    .map(this::calculate)

计算 很耗CPU。这时收益巨大。


五、什么时候不适合?

IO密集型

例如:

text 复制代码
数据库
Feign
HTTP
Redis
文件

例如:

java 复制代码
list.parallelStream()
    .forEach(x -> feign.call());

通常会更慢,甚至打爆数据库/接口。


六、为什么IO场景不适合?

因为,parallelStream 默认线程数:

text 复制代码
CPU核数

而IO:

text 复制代码
大量时间在等待

CPU其实没干活。


比如:

text 复制代码
线程1 等数据库
线程2 等网络
线程3 等Redis

CPU闲着。

所以:

parallelStream 对IO提升有限。


七、parallelStream的优势

1. 开发简单

不用:

text 复制代码
线程池
Future
CountDownLatch
CompletableFuture

一行搞定。


2. 自动线程调度

自动:

  • 分片
  • 分任务
  • 合并结果

3. CPU利用率高

例如:

8核CPU:

text 复制代码
单线程只用了1核

parallelStream:

text 复制代码
8核一起跑

八、parallelStream的缺点

很多人乱用。


缺点1:线程不受控

默认:

text 复制代码
ForkJoinPool.commonPool()

全局共享线程池。

可能:

text 复制代码
影响整个系统

缺点2:不适合数据库/Feign

例如:

java 复制代码
parallelStream()
    .forEach(x -> mapper.insert(x));

危险。

可能 瞬间几千SQL。


缺点3:线程安全问题

例如:

你这样写:

java 复制代码
List<String> result = new ArrayList<>();

list.parallelStream().forEach(x -> {
    result.add(x);
});

错误!

因为:

text 复制代码
ArrayList线程不安全

可能:

  • 数据丢失
  • 数组越界
  • ConcurrentModificationException

正确写法

用:

java 复制代码
collect(Collectors.toList())

因为 collect 内部处理了并发。


九、parallelStream为什么有时反而更慢?

因为:线程切换有成本

例如:

java 复制代码
1+1

这种极小任务。

还没切线程快。


所以:数据量小不要用

经验:

数据量 建议
<1000 通常没必要
1万+ 开始有收益
10万+ 常有明显收益

十、parallelStream不保证顺序

例如:

java 复制代码
list.parallelStream()
    .forEach(System.out::println);

输出:

text 复制代码
乱序

如果需要顺序:

java 复制代码
forEachOrdered()

但:性能会下降。


十一、真正高性能方案(推荐)

很多大系统:

不会直接用:

text 复制代码
parallelStream

而是:

自定义线程池 + CompletableFuture

因为:

  • 可控
  • 可监控
  • 可限流
  • 可隔离

例如:

java 复制代码
ExecutorService pool = Executors.newFixedThreadPool(8);

CompletableFuture.supplyAsync(() -> {
    return calculate();
}, pool);

十二、parallelStream vs 线程池

对比 parallelStream 线程池
简单 非常简单 较复杂
可控性
适合小功能 非常适合 一般
大型系统 不推荐滥用 推荐
自定义线程数 不方便 可以
隔离性

相关推荐
青山木22 分钟前
Hot 100 --- 岛屿数量
java·数据结构·算法·leetcode·深度优先·广度优先
柒星栈33 分钟前
PHP 源码怎么加密防破解?三套方案实战指南
开发语言·php·android studio
勉灬之39 分钟前
Next.js + Prisma 跨平台部署踩坑记
开发语言·javascript·ecmascript
程序员-珍40 分钟前
报错下载android sdk失败
android·java
糖果店的幽灵1 小时前
langgraph分支之 - 动态分支(Dynamic Branch)
java·前端·javascript·人工智能·langgraph
吃饱了得干活1 小时前
亿级订单表分库分表设计,从0到1全流程
java·数据库·面试
这是个栗子1 小时前
前端开发中的常用工具函数(九)
开发语言·javascript·ecmascript·at
蓝创工坊Blue Foundry1 小时前
图片文字提取到 Excel:批量任务如何先定义要交付的字段
运维·服务器·开发语言·数据库·自动化·ocr·excel
会飞的小新1 小时前
C 标准库之 <fenv.h> 详解与深度解析
c语言·开发语言·microsoft
唐青枫1 小时前
Java Spring Security 实战详解:从登录认证到 JWT 权限控制
java