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. PWN学习之整数溢出

    目录 PWN学习之整数溢出 整数溢出 溢出和回绕 漏洞多发函数 整数溢出例子 PWN学习之整数溢出 整数溢出 如果一个整数用来计算一些敏感数值,如缓冲区大小或数值索引,就会产生潜在的危险.通常情况下, ...

  2. ABP开发框架中分页查询排序的实现处理

    在ABP开发框架中应用服务层ApplicationService类中,都会提供常见的一些如GetAll.Get.Create.Update.Delete等的标准处理接口,而由于在Application ...

  3. 计算机网络-3-5-以太网MAC层及交换机

    MAC层的硬件地址 在局域网中,硬件地址又称为物理地址或者MAC地址(因为这种地址用在MAC帧中) IEEE 802标准为局域网规定了一种48位(6字节)的全球地址,固化在适配器的ROM中. 如果计算 ...

  4. 菜鸡的Java笔记 - java 双向一对多映射

    双向一对多映射    two-way    开发要求:        根据数据表的结构进行简单java类的转换:        要求实现如下的输出信息:            可以根据课程取得全部参与 ...

  5. PAT A1020——已知后序中序遍历求层序遍历

    1020 Tree Traversals Suppose that all the keys in a binary tree are distinct positive integers. Give ...

  6. 安装mysql会出现start service错误

    安装MySQL时无法启动服务(could not start the service MYSQL .Error:0)安装mysql会出现start service错误安装mysql时 配置到start ...

  7. [bzoj1146]网络管理

    发现是链上的问题,所以树链剖分发现要查询第k大,因为第k大不支持合并,所以要二分答案二分答案后相当于询问一些区间内大于某数的数个数,直接线段树套平衡树即可时间复杂度$o(nlog^{4}_n)$(跟$ ...

  8. maven私服-账号管理

    关于maven私服的相关数据: 默认账号admin,密码:admin123 这个账号是不能进行上传代码 到maven仓库的. 我们光是有admin和匿名账号是不够的,我们需要创建一个专门用来部署的账号 ...

  9. scanner对象,顺序及选择结构

    scanner对象 基本语法: Scanner s = new Scanner(System.in) 使用next()和nextLine()读取前,使用hasNext()和hasNextLine()来 ...

  10. SpringCloud微服务实战——搭建企业级开发框架(二十四):集成行为验证码和图片验证码实现登录功能

    随着近几年技术的发展,人们对于系统安全性和用户体验的要求越来越高,大多数网站系统都逐渐采用行为验证码来代替图片验证码.GitEgg-Cloud集成了开源行为验证码组件和图片验证码,并在系统中添加可配置 ...