java streamBug篇:Java8ParallelStream陷阱
误区⼀:Java 8 中的 Stream 只要使⽤ parallel 就可以并⾏处理,只要使⽤ sequential 就可以单线程处理parallel ⽅法和 sequential ⽅法不会对流产⽣任何影响,只是改动了状态位⽽已
Stream 是否并⾏取决于最后⼀次改变状态位的⽅法是 parallel 还是 sequential,下⾯两种表达式等价:
1. stream.parallel().filter(null).sequential().map(null).parallel().collect(null);
2. stream.parallel().filter(null).map(null).collect(null);
误区⼆:只要简单地加上 parallel ⽅法,就能使 Stream ⾼效并⾏
并⾏要求计算的规模要够⼤,确保在线程中运算的时间多过分配线程的开销
并⾏的数据必须是⽆序并且⽆状态的,前者会影响速度,后者会影响结果正确性(状态可以理解为 Java 中共享变量)
/* 从⼀加到⼀千万 */
public class ParallelStreamToGetSumTest {
private long num =10_000_000;
/****************************** sequectial *******************************/
@Test// 正确的顺序计算
public void sequential(){
LongStream.rangeClosed(1, num).sum());// 运⾏时间 19 milliseconds
}
@Test// 错误的顺序计算,没有考虑拆箱的开销
public void errorSequential(){
Stream.iterate(1L, i -> i +1L).limit(num)
.
reduce(0L, Long::sum));// 运⾏时间 256 milliseconds
}
/****************************** parallel *******************************/
@Test// 正确的并⾏计算
public void parallel(){
LongStream.rangeClosed(1, num).parallel().sum());// 运⾏时间 4 milliseconds
}
@Test// 错误的并⾏计算,没有考虑开箱的开销与违反了⽆序性原则(iterate 没有范围,是顺序产⽣的)
public void errorParallel(){
Stream.iterate(1L, i -> i +1L).limit(num)
.parallel().reduce(0L, Long::sum));// 运⾏时间 1680 milliseconds
}
@Test// 错误的并⾏计算,使⽤了共享变量,导致了线程竞争,并且共享变量的累加不是原⼦性的,所以结果也是错误的public void errorParallel2(){
Accumulator accumulator =new Accumulator();
Stream.iterate(1L, i -> i +1L).limit(num).parallel().forEach(accumulator::add);
al;
});// 运⾏时间 1125 milliseconds,但结果错误
}
/****************************** inner class *******************************/
private static class Accumulator {
private long total =0;
private void add(long value){
total += value;
}
}
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。