Java8并行流ParallelStream和Stream的区别就是支持并行执行,提高程序运行效率。但是如果使用不当可能会发生线程安全的问题。Demo如下:

public static void concurrentFun() {
List<Integer> listOfIntegers =
new ArrayList<>();
for (int i = 0; i <100; i++) {
listOfIntegers.add(i);
}
List<Integer> parallelStorage = new ArrayList<>() ;
listOfIntegers
.parallelStream()
.filter(i->i%2==0)
.forEach(i->parallelStorage.add(i));
System.out.println(); parallelStorage
.stream()
.forEachOrdered(e -> System.out.print(e + " ")); System.out.println();
System.out.println("Sleep 5 sec");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
} parallelStorage
.stream()
.forEachOrdered(e -> System.out.print(e + " "));
}

  程序运行结果如下:

null 72 56 58 60 74 34 36 68 70 54 28 30 50 52 26 16 44 12 14 48 22 46 40 24 42 18 20 38 6 8 10 0 null 4 82 66 84 86 78 80 76 62 64 90 92 94 88 96 98
Sleep 5 sec
null 72 56 58 60 74 34 36 68 70 54 28 30 50 52 26 16 44 12 14 48 22 46 40 24 42 18 20 38 6 8 10 0 null 4 82 66 84 86 78 80 76 62 64 90 92 94 88 96 98

  除了以上在ForEach里面添加集合元素会出现这种问题,以下这种方式也会:

              listOfIntegers
.parallelStream()
.map(e -> {
parallelStorage.add(e);
return e;
})
.forEachOrdered(e -> System.out.print(e + " "));

两个问题:

1.为什么parallelStorage的大小不固定?

2.为什么parallelStorage会有null元素?

最初我以为是因为主线程执行完成后并行流中的线程并未结束,sleep了主线程后发现结果并没有发生改变,其实我们可以认为ArrayList内部维护了一个数组Arr其定义一个变量 n用以表式这个数组的大小那么向这个ArrayList中存储数据的过程可以分解为这么几步:

1.读取数组的长度存入n

2.向这个数组中储入元素arr[n]=a

3.将n+1

4.保存n

而对于parrallelStorage元素数量不固定的原因就是多线程有可能同时读取到相同的下标n同时赋值,这样就会出现元素缺失的问题了

如何解决这个问题呢?我们可以将其转化为一个同步集合也就是

Collections.synchronizedList(new ArrayList<>()) 

在使用并行流的时候是无法保证元素的顺序的,也就是即使你用了同步集合也只能保证元素都正确但无法保证其中的顺序。

除了以上这种方式,还有什么方法可以防止并行流出现线程不安全操作?

那就是最后调用collect(Collectors.tolist()),这种收集起来所有元素到新集合是线程安全的。Demo如下:

public static void collectFun() {
List<Integer> listOfIntegers =
new ArrayList<>(); for (int i = 0; i <100; i++) {
listOfIntegers.add(i);
} List<Integer> parallelStorage = listOfIntegers
.parallelStream()
.filter(i -> i % 2 == 0)
.collect(Collectors.toList()); System.out.println(); parallelStorage
.stream()
.forEachOrdered(e -> System.out.print(e + " ")); System.out.println();
System.out.println("Sleep 5 sec");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
} parallelStorage
.stream()
.forEachOrdered(e -> System.out.print(e + " "));
}

  程序运行结果如下:

0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98
Sleep 5 sec
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98

  不光没有出现Null和数量不一致问题,还排序了!所以,在采用并行流收集元素到集合中时,最好调用collect方法,一定不要采用Foreach方法或者map方法。

Java8使用并行流(ParallelStream)注意事项的更多相关文章

  1. 避坑 | Java8使用并行流(ParallelStream)注意事项

    示例分析 /** * 避坑 | Java8使用并行流(ParallelStream)注意事项 * * @author WH.L * @date 2020/12/26 17:14 */ public c ...

  2. Java8并行流使用注意事项

    对于从事Java开发的童鞋来说,相信对于Java8的并行流并不陌生,没错,我们常常用它来执行并行任务,但是由于并行流(parallel stream)采用的是享线程池,可能会对我们的性能造成严重影响, ...

  3. JAVA使用并行流(ParallelStream)时要注意的一些问题

    https://blog.csdn.net/xuxiaoyinliu/article/details/73040808

  4. JAVA8给我带了什么——并行流和接口新功能

    流,确定是笔者内心很向往的天堂,有他之后JAVA在处理数据就变更加的灵动.加上lambda表达不喜欢都不行.JAVA8也为流在提供另一个功能——并行流.即是有并行流,那么是不是也有顺序流.没有错.我前 ...

  5. 在使用Java8并行流时的问题分析

    最近在使用Java8的并行流时遇到了坑,线上排查问题时花了较多时间,分享出来与大家一起学习与自查 // 此处为坑 List<Java8Demo> copy = Lists.newArray ...

  6. java8新特性——并行流与顺序流

    在我们开发过程中,我们都知道想要提高程序效率,我们可以启用多线程去并行处理,而java8中对数据处理也提供了它得并行方法,今天就来简单学习一下java8中得并行流与顺序流. 并行流就是把一个内容分成多 ...

  7. 【Java8新特性】关于并行流与串行流,你必须掌握这些!!

    写在前面 提到Java8,我们不得不说的就是Lambda表达式和Stream API.而在Java8中,对于并行流和串行流同样做了大量的优化.对于并行流和串行流的知识,也是在面试过程中,经常被问到的知 ...

  8. java-11-Stream优化并行流

      并行流    多线程    把一个内容分成多个数据块  不同线程分别处理每个数据块的流   串行流   单线程  一个线程处理所有数据   java8 对并行流优化  StreamAPI 通过pa ...

  9. java8学习之收集器枚举特性深度解析与并行流原理

    首先先来找出上一次[http://www.cnblogs.com/webor2006/p/8353314.html]在最后举的那个并行流报错的问题,如下: 在来查找出上面异常的原因之前,当然得要一点点 ...

随机推荐

  1. Typecho部署小破站

    写在前面 以前利用 Github Page + Hexo框架 + Next主题搭建过静态博客,没错就是那个黑白色系的网页!但是体验并不是很好,一来本身是静态网页,页面内容要修改都需要在本地修改完上传到 ...

  2. Flink 的运行架构详细剖析

    1. Flink 程序结构 Flink 程序的基本构建块是流和转换(请注意,Flink 的 DataSet API 中使用的 DataSet 也是内部流 ).从概念上讲,流是(可能永无止境的)数据记录 ...

  3. 【前端工具】nodejs+npm+vue 安装(windows)

    预备 先看看这几个是干嘛的,相互的关系是啥. nodejs是语言,类比到php. npm是个包管理,类比到composer. vue是个框架,类比到laravel. webpack是个打包工具. 先下 ...

  4. Linux&C ——信号以及信号处理

    linux信号的简单介绍 信号的捕捉和处理 信号处理函数的返回 信号的发送 信号的屏蔽 一:linux信号的简单介绍. 信号提供给我们一种异步处理事件的方法,由于进程之间彼此的地址空间是独立的,所以进 ...

  5. Git使用教程之初级入门命令行(二)

    一.Git 操作流程图 1.git --help 查看帮助 Administrator@PC-xiaobing MINGW64 /d/Git (master) $ git --help usage: ...

  6. MSSQL SQL注入 总结

    0x00 MSSQL 基础 MSSQL系统自带库和表 系统自带库 MSSQL安装后默认带了6个数据库,其中4个系统级库:master,model,tempdb和msdb:2个示例库:Northwind ...

  7. 【数据结构&算法】09-队列概念&参考源码

    目录 前言 队列的定义 队列的抽象数据类型 循环队列与链式队列对比 循环队列 特点 定义 循环队列相关计算 链式队列 定义 阻塞队列 并发队列 代码实现 循环队列代码 链式队列实现 前言 李柱明博客: ...

  8. HCNP Routing&Switching之BGP路由过滤和AS-Path-Filter

    前文我们聊了下通过修改BGP路由属性来影响路由,从而达到控制BGP路由的目的:回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15495585.html:今天我们 ...

  9. Python 爬取 煎蛋

    这个我是拿来参考的 import requests def url_open(url): response = requests.get(url) html = response.content re ...

  10. PAT A1063——set的常见用法详解

    set 常用函数实例 set是一个内部自动有序且不含重复元素的容器 (1)insert() (2)find()  st.find(*it) 找到返回其迭代器,否者返回st.end() (3)size( ...