Java8使用并行流(ParallelStream)注意事项
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)注意事项的更多相关文章
- 避坑 | Java8使用并行流(ParallelStream)注意事项
示例分析 /** * 避坑 | Java8使用并行流(ParallelStream)注意事项 * * @author WH.L * @date 2020/12/26 17:14 */ public c ...
- Java8并行流使用注意事项
对于从事Java开发的童鞋来说,相信对于Java8的并行流并不陌生,没错,我们常常用它来执行并行任务,但是由于并行流(parallel stream)采用的是享线程池,可能会对我们的性能造成严重影响, ...
- JAVA使用并行流(ParallelStream)时要注意的一些问题
https://blog.csdn.net/xuxiaoyinliu/article/details/73040808
- JAVA8给我带了什么——并行流和接口新功能
流,确定是笔者内心很向往的天堂,有他之后JAVA在处理数据就变更加的灵动.加上lambda表达不喜欢都不行.JAVA8也为流在提供另一个功能——并行流.即是有并行流,那么是不是也有顺序流.没有错.我前 ...
- 在使用Java8并行流时的问题分析
最近在使用Java8的并行流时遇到了坑,线上排查问题时花了较多时间,分享出来与大家一起学习与自查 // 此处为坑 List<Java8Demo> copy = Lists.newArray ...
- java8新特性——并行流与顺序流
在我们开发过程中,我们都知道想要提高程序效率,我们可以启用多线程去并行处理,而java8中对数据处理也提供了它得并行方法,今天就来简单学习一下java8中得并行流与顺序流. 并行流就是把一个内容分成多 ...
- 【Java8新特性】关于并行流与串行流,你必须掌握这些!!
写在前面 提到Java8,我们不得不说的就是Lambda表达式和Stream API.而在Java8中,对于并行流和串行流同样做了大量的优化.对于并行流和串行流的知识,也是在面试过程中,经常被问到的知 ...
- java-11-Stream优化并行流
并行流 多线程 把一个内容分成多个数据块 不同线程分别处理每个数据块的流 串行流 单线程 一个线程处理所有数据 java8 对并行流优化 StreamAPI 通过pa ...
- java8学习之收集器枚举特性深度解析与并行流原理
首先先来找出上一次[http://www.cnblogs.com/webor2006/p/8353314.html]在最后举的那个并行流报错的问题,如下: 在来查找出上面异常的原因之前,当然得要一点点 ...
随机推荐
- 记录一个很傻的错误(C++)
使用的vscode写代码,导入了vector,memory,然后忘了导入string.但是代码中能够提示std::string也就让我忘了导入string.然后就莫名其妙的报错了.找了很久的错.记录下 ...
- SpringCloud 2020.0.4 系列之 Sleuth + Zipkin
1. 概述 老话说的好:安全不能带来财富,但盲目的冒险也是不可取的,大胆筹划,小心实施才是上策. 言归正传,微服务的特点就是服务多,服务间的互相调用也很复杂,就像一张关系网,因此为了更好的定位故障和优 ...
- 【Java】String、StringBuffer、StringBuilder
java.lang.String类 概述 String:代表字符串.Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现 String声明为final,不可被 ...
- uni-城市列表滑动组件,点击字母跳转到指定位置
本插件由博主自主开发,比uni插件市场的城市列表滑动组件性能好,且不会出现闪屏的情况. 通过计算城市列表的高度实现滚动到指定位置,使用了uni滚动到指定位置的api city-chooce为页面入口页 ...
- python openpyxl、RESTful、Webservice接口 基础知识
最近 在做接口测试的时候,遇到如下问题:如何通过数据驱动去做批量接口测试呢,我们的测试数据放在哪里去维护?下面整理出相关点,供大家参考 1.如何维护接口测试数据:放在excel文件中,通过python ...
- java-TCP协议发送和接收数据
TCP协议接收数据的步骤: A:创建接收数据的Socket对象 创建对象的时候要指定端口 B:监听客户端连接 等待客户端连接 C:获取Socket对象的输入流(字节流) D:读数据,并显示在控制台 E ...
- [cf674E]Bear and Destroying Subtrees
令$f_{i,j}$表示以$i$为根的子树中,深度小于等于$j$的概率,那么$ans_{i}=\sum_{j=1}^{dep}(f_{i,j}-f_{i,j-1})j$ 大约来估计一下$f_{i,j} ...
- App 端自动化的最佳方案,完全解放双手!
1. 前言 大家好,我是安果! 之前写过一篇文章,文中提出了一种方案,可以实现每天自动给微信群群发新闻早报 如何利用 Python 爬虫实现给微信群发新闻早报?(详细) 但是对于很多人来说,首先编写一 ...
- restTemplate的问题-feign的项目
restTemplate的问题 1.场景描述 在使用feign的项目中,偶然的使用到了restTemplate 在普通方法调用是可以访问的,一旦使用了restTemplate,出现报错 比如: 百度 ...
- 在spring启动后执行代码
如果spring的项目直接监听tomcat启动对于 操作来说有很大难度,bean没有初始化,接口不能直接调用等等,所以我们代码执行要在spring启动之后执行项目 package com.java71 ...