我有如下代码,
List<String> itemIdList=new ArrayList<>();
List<String> linkedItemIds=new ArrayList<>();
items.parallelStream().forEach(item -> {
itemIdList.add(item.getId());
validateLinkedItemStatus(order, error);
if (CollectionUtils.isNotEmpty(error)) {
//some db validation
return;
}
linkedItemIds.add(item.getLinkedId());
});
由于项目数量较多,我想并行执行此任务,但每次执行此循环时,相同项目的 itemIdList 大小都不同。有人可以告诉我这里出了什么问题吗?
该问题是由于错误使用副作用造成的。 Stream API 文档明确不鼓励这种用法:
一般来说,不鼓励流操作的行为参数产生副作用,因为它们通常会导致无意中违反无状态性要求,以及其他线程安全隐患。 如果行为参数确实有副作用,除非明确说明,否则无法保证这些副作用对其他线程的可见性,也无法保证同一流管道中“相同”元素上的不同操作在同一个线程中执行。
由于您需要
id
和可选的 linkedId
,因此您可以做的是在收集之前使用 ids 的包装对象。
public record IdWrapper(String id, String linkedId) {
public IdWrapper(String id) {
this(id, null);
}
}
并有条件地在对象中添加链接的 id。
List<IdWrapper> wrappers = items.parallelStream()
.map(item -> {
validateLinkedItemStatus(order, error);
return CollectionUtils.isNotEmpty(error) ? new IdWrapper(item.id()) : new IdWrapper(item.id(), item.linkedId());
})
.toList();//or collect(Collectors.toList()) depending on the exact scenario