Stream 是JAVA8引入的一个新的抽象,为了提高性能同时也加入了parallelStream(并行流
)
看下面一段代码
Map<String,String> map = new HashMap<>();
map.put("1","2");//1
List<Map<String,Integer>> mapsL = new ArrayList<>();//2
for(int i=0;i<100000;i++){//3
Map<String,Integer> map1 = new HashMap<>();
map1.put("key",i);
mapsL.add(map1);
}
List<Map<String,Integer>> maps2 = new ArrayList<>();
mapsL.parallelStream().filter(
iter-> iter.get("key") <20000
).forEach(maps2::add);//4
if(maps2.size()<20000){//5
System.out.println("forEach Error !"+maps2.size());//6
}
从表面看上去相安无事,输出语句并不会运行。
其实并不然
你把这个段代码粘贴并运行之后,会发现输出语句是有输出的。
这个时候心里就会产生疑问这是为什么呢?所有的操作看上去都是合理的而且符合java语法的。
我们一起来重读一下代码
- 代码1到3为正常创建添加操作,模仿我们从数据源查出的数据集
- 代码4是一个并行的流
- 过滤key对应的值小于20000的操作
- 将过滤后的值add到naps2中
- 5是逻辑判断
我们在面对一个巨型的集合时候,Stream的串行操作是无法我们对性能的追求的,那这个时候最好的操作就是采用多线程或者parallelStream并行流,无论是前者还是后者,都要面临一个问题——线程安全。
哦,这个时候就不难明白为啥上面maps2的SIZE会小于20000,罪魁祸首就是上面的代码4,
- ArrayList是一个非线程安全类
- forEach 的操作是无顺序控制的
问题找到了,我相信大家会有更多的办法去解决 ,无论是使用线程安全的Vector ,亦或者使用forEachOrdered,或者不做迭代操作直接使用.collect(Collectors.toList()) 的操作都是可以解决上面的问题的。
Map<String,String> map = new HashMap<>();
map.put("1","2");
List<Map<String,Integer>> mapsL = new ArrayList<>();
for(int i=0;i<100000;i++){
Map<String,Integer> map1 = new HashMap<>();
map1.put("key",i);
mapsL.add(map1);
}
for(int i=0;i<10000;i++){
List<Map<String,Integer>> list= mapsL.parallelStream().filter(
iter-> iter.get("key") <20000
).collect(Collectors.toList()); //方案1 推荐
List<Map<String,Integer>> maps2 = new Vector<>();
mapsL.parallelStream().filter(
iter-> iter.get("key") <20000
).forEach(maps2::add); //方案2
List<Map<String,Integer>> maps3 = new ArrayList<>();
mapsL.parallelStream().filter(
iter-> iter.get("key") <20000
).forEachOrdered(maps3::add); // 方案3
if(maps3.size()<20000){
System.out.println("forEach Error !"+maps2.size());
}
if(maps2.size()<20000){
System.out.println("forEach Error !"+maps2.size());
}
if(list.size()<20000){
System.out.println("Collect Error !"+list.size());
}
//方案 N。。。。。。。。。。。。。
}
网友评论