谨慎使用 Java8 新特性 parallelStream

本文探讨了Java8的ParallelStream及其潜在陷阱,包括线程安全问题和并行处理不一定并行的情况。使用ParallelStream时需谨慎,考虑业务场景是否需要并行、任务独立性以及执行顺序。并行流依赖于ForkJoinPool,其并行度取决于CPU核心数。通过测试示例揭示了资源竞争可能导致的串行执行问题。
摘要由CSDN通过智能技术生成

1. 前言

在说 parallelStream 之前, 一定要了解 Stream 以及它的基本操作

2. 什么是 ParallelStream

上文讲到的 Java8 Stream 流在执行时候是串行化的, 如果说任务执行的耗时比较长, 可以使用 Stream 的 "兄弟流" ParallelStream

防止误导, 并非耗时就一定要使用并行, 根据不同的业务场景, 合理的使用即可

parallelStream 是一种并行流, 意思为处理任务时并行处理, 这里和并发编程就有了千丝万缕的关系

前提是硬件支持, 如果单核 CPU, 只会存在并发处理, 而不会并行

这篇文章主要是说明 ParallelStream 其中一个可能为成为埋雷的点

项目中业务使用的并行流真的会都并行处理么?

3. 如何使用 ParallelStream

ParallelStream 在使用上与 Stream 无区别, 本质返回的都是一个流, 只不过底层处理时 根据条件判断是并行或者是串行

并行流并不会按照原本的顺序轨迹执行, 而是 随机执行, 当然对于这种 forEach 输出也可以做到顺序串行, 但这个不在文章中的重点

4. ForkJoinPool

相信如果在项目中实际使用过并行流的小伙伴, 一定会知道 ForkJoinPool

没错, 并行流底层就是使用的 ForkJoinPool, 一种 工作窃取算法线程池

ForkJoinPool 的优势在于, 可以充分利用多 CPU 的优势,把一个任务拆分成多个"小任务", 把多个"小任务"放到多个处理器核心上并行执行; 当多个"小任务"执行完成之后, 再将这些执行结果合并起来

5. 并行流的陷阱

5.1 线程安全问题

只要是并行处理, 如果在流程中的操作产生了竞态条件, 就会存在线程安全问题

这里举个例子进行说明具体问题

public static void main(String[] args) {
    List<Integer> integerList = Lists.newArrayList();
    List<String> strList = Lists.newArrayList();

    int practicalSize = 1000000;

    for (int i = 0; i < practicalSize; i++) {
        strList.add(String.valueOf(i));
    }

    strList.parallelStream().forEach(each -> {
        integerList.add(Integer.parseInt(each));
    });

    log.info("  >>> integerList 预计长度 :: {}", practicalSize);
    log.info("  >>> integerList 实际长度 :: {}", integerList.size());
}
/**
 * >>> integerList 预估长度 :: 1000000
 * >>> integerList 实际长度 :: 211195
 */
复制代码

上面这段程序运行流程说明如下:

1、创建了两个 List, 分别是 String、Integer 类型

2、向 strList 插入 1000000 条记录

3、使用并行流将 strList 中的数据格式化为 Integer 并添加到 integerList

4、输出 integerList 预计长度以及实际长度

正常情况下, 我们是希望 integerList 最终输出 1000000

但是会因为并

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值