parallelStream().forEach 给出不一致的输出

问题描述 投票:0回答:1

我有如下代码,

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 大小都不同。有人可以告诉我这里出了什么问题吗?

java foreach parallel-processing stream
1个回答
0
投票

该问题是由于错误使用副作用造成的。 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
© www.soinside.com 2019 - 2024. All rights reserved.