JDK8新特性并行流-ParallelStream

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiakexiaohu/article/details/86613184
package chap07.ParalleDemo;

import java.util.function.Function;
import java.util.stream.LongStream;
import java.util.stream.Stream;

class Accumlator{
    public long total = 0;

    public void add(long value) {
        total += value;
    }
}
public class ParallelTest {
    public static void main(String[] args) {
        //需求:使用并行流测试自然数n的累加效率

        //测试顺序流
        System.out.println("Sequential sum done in :"+ measureSumPerf(ParallelTest::sequentialSum,1_000_000_0)+"mesecs");

        //测试传统迭代
        System.out.println("Iterative sum done in :" + measureSumPerf(ParallelTest::iterativeSum, 1_000_000_0) + "mesecs");

        //测试并行流
        System.out.println("Parallel sum done in :" + measureSumPerf(ParallelTest::parallelStream, 1_000_000_0) + "mesecs");

        //测试非Long装箱的并行流
        System.out.println("Parallel sum done in :" + measureSumPerf(ParallelTest::rangedSum, 1_000_000_0) + "mesecs");

        //错误使用并行流示例
        System.out.println("SideEffect parallel sum done in :" + measureSumPerf(ParallelTest::sideEffectParallelSum, 1_000_000_0) + "mesecs");

    }

    //1.传统外部迭代实现(等价于2的实现)
    public static long iterativeSum(long n) {
        long res = 0;
        for (long i = 1L; i <= n; i++) {
            res += i;
        }
        return res;
    }

    //2.使用BinaryOperator归约实现
    public static long sequentialSum(long n) {
        return Stream.iterate(1L, i -> i + 1).limit(n).reduce(0L, Long::sum);

    }

    //3.改进使用并行流
    public static long parallelStream(long n) {
        return Stream.iterate(1L,i->i+1).limit(n).parallel().reduce(0L,Long::sum);
    }

    //4.针对iterator并行装箱拆箱改进方法:使用LongStream.rangeClosed来直接产生原始类型的long数字,再使用并行流
    public static long rangedSum(long n) {
        return LongStream.rangeClosed(1,n).parallel().reduce(0L, Long::sum);
    }

    //5.针对4的错误使用并行流
    public static long sideEffectParallelSum(long n) {
        Accumlator accumlator = new Accumlator();
        LongStream.rangeClosed(1, n).parallel().forEach(accumlator::add);
        return accumlator.total;
    }

    //定义测试函数
    public static long measureSumPerf(Function<Long, Long> adder, long n) {
        long fastest = Long.MAX_VALUE;
        //迭代10次
        for (int i = 0; i < 10; i++) {
            long start=System.nanoTime();
            long sum = adder.apply(n);
            long duration=(System.nanoTime()-start)/1_000_000;
            System.out.println("Result: " + sum);
            //取最小值
            if (duration < fastest) {
                fastest = duration;
            }
        }
        return fastest;
    }
}

测试效率结果:

1.Sequential sum done in :70mesecs

2.Iterative sum done in :2mesecs

3.Parallel sum done in :76mesecs

4.Parallel sum done in :0mesecs

5.SideEffect parallel sum done in :0mesecs

Summary:从以上结果1和3可以看出并行流效率反而不如传统迭代方式,并不是说并行流不行。而是iterator这里对Long存在装箱和拆箱的过程,所以效率反而不如传统long的数据的叠加。针对Long的装箱过程,采用4的LongStream.rangeClosed进行改进,该流可以直接对原始long数据进行操作,所以效率明显提高。最后针对5不正确使用并行foreach操作,具体结果如下。它会改变多个县城共享的对象的可变状态,因此使用并行流必须主意避免多线程同时访问叠加器,具体原因:在执行total+=value操作时,并不是原子操作。

Result: 6048226861981
Result: 4705973712057
Result: 6101215404420
Result: 5097981782822
Result: 7411387445417
Result: 2857628543763
Result: 5263044807223
Result: 5587422458217
Result: 2451583038513
Result: 4380427335916
SideEffect parallel sum done in :0mesecs

猜你喜欢

转载自blog.csdn.net/xiakexiaohu/article/details/86613184