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() 并进行充分测试。

相关推荐
历程里程碑5 分钟前
子串-----和为 K 的子数组
java·数据结构·c++·python·算法·leetcode·tornado
liu****19 分钟前
Qt进阶实战:事件处理、文件操作、多线程与网络编程全解析
开发语言·网络·数据结构·c++·qt
寄存器漫游者41 分钟前
数据结构 二叉树核心概念与特性
数据结构·算法
皮皮哎哟1 小时前
数据结构:从队列到二叉树基础解析
c语言·数据结构·算法·二叉树·队列
一匹电信狗1 小时前
【高阶数据结构】并查集
c语言·数据结构·c++·算法·leetcode·排序算法·visual studio
Hello World . .1 小时前
数据结构:二叉树(Binary tree)
c语言·开发语言·数据结构·vim
DeeplyMind2 小时前
少儿科技启蒙教材:《数据结构启蒙》
数据结构·计算机科学·少儿科技读物·蓝桥杯青少组
划破黑暗的第一缕曙光2 小时前
[数据结构]:6.二叉树链式结构的实现2
c语言·数据结构·二叉树
浅念-2 小时前
C语言——自定义类型:结构体、联合体、枚举
c语言·开发语言·数据结构·c++·笔记·学习·html
仰泳的熊猫3 小时前
题目1433:蓝桥杯2013年第四届真题-危险系数
数据结构·c++·算法·蓝桥杯·深度优先·图论