parallelStream是jdk8引入的特性,其实就是一个并行执行的流,它通过默认的ForkJoinPool,底层是窃取算法,利用了现代硬件设备多核,可能提高你的多线程任务的速度。
1.两种写法都行:stream().parallel()或者parallelStream()。
2.numbers.parallelStream().forEach会打乱顺序,如果想要案顺序处理,要用numbers.parallelStream().forEachOrdered,但forEachOrdered可能会失去平行化的一些优势。
3.用法例子:
For1:
List<AbcDto> results = refers.parallelStream().map(t -> {
AbcDto dto = AbcDto.builder()
....
.build();
doFormat(t, dto);
return dto;
}).collect(Collectors.toList());
4.并行流要注意的坑:
坑1:
parallelStream的后面如果是foreach,且foreach后面还有代码,则就会并不等待parallelStream执行完就跑了后面的代码,应该改为map或filter处理【但parallelStream当前主线程也会做为线程池一员去执行foreach中逻辑的,理论上不会出现这种情况的!】。
示例:
List<CommentMngDto> records = new ArrayList<>(pageableInfo.getRecords().size());
PageableInfo<CommentMngDto> result = new PageableInfo<>(pageableInfo.getPageNum(), pageableInfo.getPageSize(), pageableInfo.getTotal(), records);
pageableInfo.getRecords().parallelStream().forEach(com -> {
CommentMngDto dto = new CommentMngDto();
dto.fromComment(com, assetService);
Organization org = organizationService.getOrgByCode(com.getOrgCode());
Optional.ofNullable(org).ifPresent(o -> dto.setOrgName(I18nUtil.getMultiLang(o.getNameMultil(), null)));
records.add(dto);
});
return result;
问题:返回的records数据少了。
最终换成:
List<CommentMngDto> records = pageableInfo.getRecords().parallelStream().map(com -> {
CommentMngDto dto = new CommentMngDto();
dto.fromComment(com, assetService);
Organization org = organizationService.getOrgByCode(com.getOrgCode());
Optional.ofNullable(org).ifPresent(o -> dto.setOrgName(I18nUtil.getMultiLang(o.getNameMultil(), null)));
return dto;
}).sorted(Comparator.comparing(CommentMngDto::getCreateTime).reversed()).collect(Collectors.toList());
PageableInfo<CommentMngDto> result = new PageableInfo<>(pageableInfo.getPageNum(), pageableInfo.getPageSize(), pageableInfo.getTotal(), records);
return result;
坑2:就是parallelStream中处理逻辑代码,如果涉及到一些集合类的add等操作的,要用线程安全的集合类,如CopyOnWriteArrayList、ConcurrentHashMap等。
所以,可见,坑1是不存在的,坑1中出现问题的根源是坑2,所以,还是可以在parallelStream放心使用forEach的。
坑3:parallelStream无法传递threadLocal的值。
有些人说,我用TransmittableThreadLocal不行吗? 不行,还真不行。
如何解决,使用TransmittableThreadLocal,并且,
在启动的VM参数加上:
-javaagent:D:/programfiles/apache-maven-3.6.3/m2/myrepository/com/alibaba/transmittable-thread-local/2.12.2/transmittable-thread-local-2.12.2.jar
当然,如果想控制并发数,还可以加上:
-Djava.util.concurrent.ForkJoinPool.common.parallelism=16