一、使用场景
- 先贴代码
java
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
List<Integer> integerList = new ArrayList<>();
int num = 10000;
for (int i = 0;i<num;i++){
stringList.add(String.valueOf(i));
}
stringList.parallelStream().forEach(str->{
integerList.add(Integer.parseInt(str));
});
System.out.println(stringList.size());
System.out.println(integerList.size());
}
--- 下面是执行一次的结果 ---
10000
5769
可以看出来:parallelStream实际上是为每一个流创建了一个线程,去执行后面的任务。由于是多线程环境下,流后面的foreach、map里的逻辑如果有共享变量需要自行保证线程安全。这里就是因为ArrayList不是线程安全的,所以integerList与stringList的数据不一致。
- 结论:用于多线程执行任务
二、进阶使用
上面的代码线程不安全,如何修改?
方式一,将integerList的实现改为线程安全的List
java
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
List<Integer> integerList = Collections.synchronizedList(new ArrayList<>());
int num = 10000;
for (int i = 0;i<num;i++){
stringList.add(String.valueOf(i));
}
stringList.parallelStream().forEach(str->{
integerList.add(Integer.parseInt(str));
});
System.out.println(stringList.size());
System.out.println(integerList.size());
}
--- 下面是执行一次的结果 ---
10000
10000
方式二:使用collect
parallelStream的map,collect,flatMap,reduce等操作已经自行保证了线程安全
java
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
int num = 10000;
for (int i = 0; i < num; i++) {
stringList.add(String.valueOf(i));
}
List<Integer> integerList = stringList
.parallelStream()
.map(Integer::parseInt)
.collect(Collectors.toList());
System.out.println(stringList.size());
System.out.println(integerList.size());
}
三、常用案例
有时候,我们会for循环调用service获取多个List<T>的,最后把所有获取到的List<T>汇总起来,添加到结果集里。
- 用List<callable<List<T>>> callableList将多个并发任务添加进去,然后使用List<Future> futures = threadPoolExecutor.invokeAll(callableList),最后将所有future的调用结果get出来,添加到result
- 用parallelStream().map.collect
java
List<User> resultList = paramList
.parallelStream()
// 执行业务逻辑,根据参数查询n次
.map(param -> {
//todo 构建参数
return userService.query(param);
})
.collect(Collectors.toList());