1. 前言
今天面试被问到,为什么这里要用Stream提供的并行流?我突然懵了,可能习惯性的用并行流了,觉得并行流效率要比顺序流快。但是真的是这样吗?我才仔细阅读我自己写的这段代码,做过过滤和排序,这不完了,都排序了,并行流能好使吗,赶紧改回了顺序流,再仔细看一下,数据才十来条,这就更没必要使用并行流了。面试完,心想今天又凉了,赶紧复盘一下吧,到家查阅了相关资料,总结了如下内容。
2. 简单介绍Parallel Stream
Stream产生于Java8的新特性中,它为我们提供了两种流处理的方式一种是Sequential Stream顺序流,另一种就是本文要着重讲的Parallel Stream并行流。顺序流很好理解,就是按顺序进行遍历处理,并行流相对来说比较复杂,它是通过ForkJoinPool借助工作窃取算法将任务拆解成多个子任务,利用分治的思想处理任务。
如果大家不懂Java8 Stream的使用方法可以看我这篇文章让Java8的Stream更简单。
如果大家不懂什么是ForkJoinPool可以看我的另一篇文章你了解Java中的ForkJoin吗?
3. 适用场景
使用并行流的前提条件是多核CPU,单核CPU也没有使用的必要
- 大规模数据集,只有数据集够大,才能发挥并行的优势,否则并行流还很得增加很多额外的开销(线程调度、数据切分等)
- 复杂的计算场景,并行流可以通过多核的优势加速计算过程。
- 无状态转换的操作,比如map、filter表现更好,聚合操作也还可以,这些操作不依赖其它元素的状态。有状态的转换操作的如sorted这种就会出现性能下降,甚至是结果错误。
4. 注意事项
- 并行流采用多线程的方式执行,因此需要注意线程安全问题。
- 并行流采用多线程的方式执行,因此ThreadLocal也要注意尽量别用。
- 并行流中尽量避免使用有状态转换的操作,比如sorted。
- 性能评估和测试,对于有明显性能提升的地方再使用并行流,没有性能提升尽量不使用并行流。
- 并行流可能会带来更高的内存占用,处理大规模数据集时需要确保有足够的内存支持并行流的执行。
- 对于操作的数据结构是否支持分割也很重要,如HashSet。
- 避免在并行流中使用collectors.groupingBy、collectors.toMap,替代为collectors.groupingByConcurrent、collectors.toConcurrentMap,或直接使用串行流。
5. 总结
其实在日常开发中,对于大部分场景下并行流并不适用,顺序流更加稳妥。我们不应该无脑去相信并行流会比较快,反而在使用并行流的时候要非常慎重,这种地方出现问题往往并不好排查,大部分场景下也并不能起到提效的作用,甚至是因为创建并行执行的环境降低效率。
大家应该仔细去检查一下,自己在项目中是否无脑用并行流,及时止损,防止出现严重的生产问题。
文章虽然不长,但是我感觉自己对并行流的认知更强了,以后不会再乱用了,收获满满!以后在使用工具中也要多去问问自己为什么要这么用,这样用真的好吗?
如果大家感觉有帮助,请大家点赞收藏+关注,有问题可以在评论区评论哦!