Java8集合list.parallelStream() 和 list.stream() 区别

list.parallelStream()list.stream() 的主要区别在于并行处理能力

1. 核心区别

  • list.stream():顺序流,单线程顺序处理

  • list.parallelStream():并行流,自动使用多线程并行处理

2. 执行方式对比

java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 顺序流 - 单线程顺序执行
numbers.stream()
       .map(n -> {
           System.out.println(Thread.currentThread().getName() + ": " + n);
           return n * 2;
       })
       .forEach(System.out::println);

// 输出(大致):
// main: 1
// 2
// main: 2
// 4
// main: 3
// 6
// 并行流 - 多线程并行执行
numbers.parallelStream()
       .map(n -> {
           System.out.println(Thread.currentThread().getName() + ": " + n);
           return n * 2;
       })
       .forEach(System.out::println);

// 输出(可能):
// ForkJoinPool.commonPool-worker-1: 3
// ForkJoinPool.commonPool-worker-2: 2
// main: 1
// 6
// 4
// 2
// ...

3. 性能特点

特性 stream() parallelStream()
线程使用 单线程 ForkJoinPool 线程池
数据顺序 保持顺序 可能乱序(除非用forEachOrdered
适用场景 小数据量、顺序敏感操作 大数据量、CPU密集型计算
开销 有线程创建、同步开销

4.使用场景建议

适合使用 stream() 的情况:

java 复制代码
// 1. 数据量小
List<String> smallList = ...;
smallList.stream()...

// 2. 需要保持顺序
list.stream()
    .sorted()           // 排序操作
    .forEach(...);      // 顺序重要

// 3. I/O密集型操作(文件读写、网络请求)
list.stream()
    .map(this::readFromFile)  // I/O操作通常不适合并行
    .collect(Collectors.toList());

// 4. 有状态操作
list.stream()
    .skip(2)      // 跳过前两个
    .limit(10)    // 限制数量
    .collect(...);

适合使用 parallelStream() 的情况

java 复制代码
// 1. 大数据集(通常 > 10000个元素)
List<Integer> largeList = ...;
largeList.parallelStream()
         .map(x -> heavyCalculation(x))  // 耗时计算
         .collect(Collectors.toList());

// 2. CPU密集型计算
list.parallelStream()
    .map(this::complexMathOperation)  // 复杂数学运算
    .reduce(0, Integer::sum);

// 3. 操作之间无依赖
list.parallelStream()
    .filter(this::isValid)      // 过滤可以并行
    .map(this::transform)       // 映射可以并行
    .collect(Collectors.toList());

5. 重要注意事项

线程安全问题

java 复制代码
List<Integer> result = Collections.synchronizedList(new ArrayList<>());

// ❌ 错误:并行修改共享状态
List<Integer> unsafeList = new ArrayList<>();
list.parallelStream()
    .forEach(unsafeList::add);  // 可能抛出ConcurrentModificationException

// ✅ 正确:使用线程安全集合或避免共享状态
list.parallelStream()
    .collect(Collectors.toList());  // 使用内置收集器

顺序保证:

java 复制代码
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

// 顺序不确定
list.parallelStream()
    .forEach(System.out::print);  // 可能输出:3 1 4 2 5

// 保持顺序
list.parallelStream()
    .forEachOrdered(System.out::print);  // 总是输出:1 2 3 4 5

6. 性能测试示例

java 复制代码
public class StreamBenchmark {
    public static void main(String[] args) {
        List<Integer> numbers = IntStream.rangeClosed(1, 1_000_0000)
                                         .boxed()
                                         .collect(Collectors.toList());
        
        // 顺序流
        long start = System.currentTimeMillis();
        long sum1 = numbers.stream()
                          .mapToLong(i -> (long)i * i)
                          .sum();
        long time1 = System.currentTimeMillis() - start;
        
        // 并行流
        start = System.currentTimeMillis();
        long sum2 = numbers.parallelStream()
                          .mapToLong(i -> (long)i * i)
                          .sum();
        long time2 = System.currentTimeMillis() - start;
        
        System.out.println("顺序流时间: " + time1 + "ms");
        System.out.println("并行流时间: " + time2 + "ms");
        System.out.println("结果一致: " + (sum1 == sum2));
    }
}

7. 最佳实践建议

  1. 先测试,再选择:对于关键代码,先测试两种方式的性能

  2. 默认用顺序流:除非有明确证据表明并行流更好

  3. 考虑NQ模型:只有当 N(数据量) × Q(每个元素计算量)较大时,并行才有效

  4. 避免副作用:并行流中避免修改外部状态

  5. 注意资源限制:并行流使用公共ForkJoinPool,可能影响其他并行任务

总结

  • stream():简单、可预测、适用于大多数场景

  • parallelStream():性能可能更好,但需要满足特定条件,且要注意线程安全和顺序问题

简单选择原则 :默认使用 stream(),只有当处理大数据集且操作耗时的情况下,才考虑使用 parallelStream() 并进行充分测试。

相关推荐
CSharp精选营3 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假7 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠8 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦14 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠15 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾15 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82116 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q16 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒16 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
世人万千丶16 天前
成语接龙小应用 - HarmonyOS ArkUI 开发实战-TextInput与List列表-PC版本
华为·list·harmonyos·鸿蒙·鸿蒙系统