jdk8使用并行流(ParallelStream)存在的问题


 
 
  1. public static void main(String[] args) throws InterruptedException
  2. {
  3. Integer[] intArray = { 1, 2, 3, 4, 5, 6, 7, 8};
  4. List<Integer> listOfIntegers =
  5. new ArrayList<>(Arrays.asList(intArray));
  6. List<Integer> parallelStorage = new ArrayList<>(); //Collections.synchronizedList(new ArrayList<>());
  7. listOfIntegers
  8. .parallelStream()
  9. // Don't do this! It uses a stateful lambda expression.
  10. .map(e -> {
  11. parallelStorage.add(e);
  12. return e;
  13. })
  14. .forEachOrdered(e -> System.out.print(e + " "));
  15. System.out.println();
  16. parallelStorage
  17. .stream()
  18. .forEachOrdered(e -> System.out.print(e + " "));
  19. System.out.println();
  20. System.out.println( "Sleep 5 sec");
  21. TimeUnit.SECONDS.sleep( 5);
  22. parallelStorage
  23. .stream()
  24. .forEachOrdered(e -> System.out.print(e + " "));
  25. }

运行以上代码你可能会得到以下几种结果:


 
 
  1. Result 1:
  2. 1 2 3 4 5 6 7 8
  3. null 3 8 7 1 4 5 6
  4. Sleep 5 sec
  5. null 3 8 7 1 4 5 6
  6. Result 2
  7. 1 2 3 4 5 6 7 8
  8. 6 2 4 1 5 7 8
  9. Sleep 5 sec
  10. 6 2 4 1 5 7 8

两个问题:

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

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

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

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

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

3.将n+1

4.保存n

A.对于元素中有null值的情况:

考虑三个线程的关系


如果是这种情况就会出现null元素;

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

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

Collections.synchronizedList(new ArrayList<>())
 
 

但是要注意的是,在使用并行流的时候是无法保证元素的顺序的,也就是即使你用了同步集合也只能保证元素都正确但无法保证其中的顺序,这个在Oracle官方文档也有说明,不要使用有副作用的lambda表达式,那么什么是有副作用的lambda表达式呢?

官方文档说“ A stateful lambda expression is one whose result depends on any state that might change during the execution of a pipeline.”就是说这种lambda表达式的结果会在管道执行的过程中发生变化



        

关注小编微信公众号(java交流),回复520免费领取java电子书资料!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值