zoukankan      html  css  js  c++  java
  • 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方法。

  • 相关阅读:
    POJ 1795 DNA Laboratory
    CodeForces 303B Rectangle Puzzle II
    HDU 2197 本源串
    HDU 5965 扫雷
    POJ 3099 Go Go Gorelians
    CodeForces 762D Maximum path
    CodeForces 731C Socks
    HDU 1231 最大连续子序列
    HDU 5650 so easy
    大话接口隐私与安全 转载
  • 原文地址:https://www.cnblogs.com/edda/p/15055580.html
Copyright © 2011-2022 走看看