并行流parallelStream注意事项
1、parallelStream是线程不安全的
2、parallelStream适用的场景是CPU密集型的,只是做到别浪费CPU,假如本身电脑CPU
的负载很大,那还到处用并行流,那并不能起到作用
3、I/O密集型 磁盘I/O、网络I/O都属于I/O操作,这部分操作是较少消耗CPU资源,一般并
行流中不适用于I/O密集型的操作,就比如使用并流行进行大批量的消息推送,涉及到了
大量I/O,使用并行流反而慢了很多
4、在使用并行流的时候是无法保证元素的顺序的,也就是即使你用了同步集合也只能保
证元素都正确但无法保证其中的顺序
解决并行流的线程安全问题:多线程下,使用并行流会有线程安全的问题
根据需要进行不同的处理:
1、使用同步代码块 synchronized (比如使用forEach循环处理时)
2、使用线程安全的集合 Vector、Collections.synchronizedList(list)
3、调用Stream流的 collect/toArray 方法
普通for循环、串行流、并行流在循环处理数据时性能对比:
测试代码:
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for(int i = 0; i < 15000000;i++){
list.add("a"+i);
}
StopWatch stopWatch = new StopWatch();
stopWatch.start();
for(int i = 0; i < list.size();i ++){
if(list.get(i).endsWith("0000000")){
System.out.println("END==================");
}
}
stopWatch.stop();
System.out.println("=====for===耗费:"+stopWatch.getTime());
stopWatch.reset();
stopWatch.start();
list.stream().filter(x -> x.endsWith("0000000")).forEach(a->{
System.out.println("END==================");
});
stopWatch.stop();
System.out.println("=====stream===耗费:"+stopWatch.getTime());
stopWatch.reset();
stopWatch.start();
list.parallelStream().filter(x -> x.endsWith("0000000")).forEach(a->{
System.out.println("END==================");
});
stopWatch.stop();
System.out.println("=====parallelStream===耗费:"+stopWatch.getTime());
}
总结: 修改上面代码数据量的大小结果不同,
可以看到,串行化流在数据量很小的情况下,性能最差。而并行化流则处于波动的状态。
所以单单从数据量上可以看出:
for循环的性能随着数据量的增加性能也越来越差。
串行化流则在数据量小的情况下性能差,数据量中、大的时候性能略高于for循环,但当数据量特别大时,性能也变得越差。
并行化流受CPU核数的影响,在本机2核下,在数据量小的情况下性能略高于串行化流,略低于for循环,在数据量中的情况下差不多,在数据量比较大时性能最差,但当数据量特别大时,性能也变得更好。
如果想要使用parallelStream想提高性能,一定要根据实际情况做好测试,因为并行化的流性能不一定比串行化流性能高。