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

相关推荐
Z1Jxxx3 小时前
0和1的个数
数据结构·c++·算法
ldccorpora3 小时前
Chinese News Translation Text Part 1数据集介绍,官网编号LDC2005T06
数据结构·人工智能·python·算法·语音识别
AuroraWanderll4 小时前
类和对象(六)--友元、内部类与再次理解类和对象
c语言·数据结构·c++·算法·stl
leaves falling4 小时前
c语言-给定两个数,求这两个数的最大公约数
数据结构·算法
想做后端的小C4 小时前
数据结构:线性表原地逆置
数据结构·考研
jikiecui4 小时前
信奥崔老师:三目运算 (Ternary Operator)
数据结构·c++·算法
无限进步_4 小时前
【C语言&数据结构】另一棵树的子树:递归思维的双重奏
c语言·开发语言·数据结构·c++·算法·github·visual studio
志摩凛4 小时前
Element UI 长表单校验失败后自动展开折叠面板并滚动定位
数据结构·vue.js