gpt4 book ai didi

Java 流 forEach concurrentModificationException 异常行为

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:48:23 26 4
gpt4 key购买 nike

当我运行下面的代码时

List<Integer> list = IntStream.range(0,10).boxed().collect(Collectors.toList());
list.stream().forEach(i -> {
System.out.println("i:" +i);
if (i==5) {
System.out.println("..adding 22");
list.add(22);
}
});

我得到以下输出:

i:0
i:1
i:2
i:3
i:4
i:5
..adding 22
i:6
i:7
i:8
i:9
Exception in thread "main" java.util.ConcurrentModificationException

为什么代码会超过索引 5?我没想到输出中会出现以下几行:

i:6
i:7
i:8
i:9

我在这里遗漏了一些关于 forEach 行为的信息。该文档确实声明“此操作的行为是明确不确定的。”并继续谈论并行流。我希望并行流以任何顺序执行 forEach,但串行流肯定会串行执行提供给 forEach 的 Consumer 吗?如果是这样,为什么 Java 允许代码超越索引 5 处生成的异常?这里有一个线程,对吗?

提前致谢。

编辑:感谢您到目前为止的回答。明确地说,我的观点是,如果我这样做:

   for(int i: list){
System.out.println("i:" +i);
if(i==5) {
System.out.println("..adding 22");
list.add(22);
}
}

我明白了:

i:0
i:1
i:2
i:3
i:4
i:5
..adding 22
Exception in thread "main" java.util.ConcurrentModificationException

但我没有在 forEach 中得到它。因此,串行流 forEach 似乎与迭代器不同,无论是手摇的 (Iterator iter = list.iterator...) 还是增强的 for 循环迭代器。这出乎我的意料。但从答案看来,这是出于“性能原因”。但这仍然是……出乎意料的。只是为了好玩,我尝试了一个 1m 元素的列表:

    List<Integer> list = IntStream.range(0,1000000).boxed().collect(Collectors.toList());
list.stream().forEach(
i -> {
if(i%250000==0)
System.out.println("i:" +i);
if(i>999997)
System.out.println("i:" +i);

if(i==5) {
System.out.println("..adding 22");
list.add(22);
}}
);

我得到了(现在预期的)以下输出:

i:0
..adding 22
i:250000
i:500000
i:750000
i:999998
i:999999
Exception in thread "main" java.util.ConcurrentModificationException

如前所述,检查似乎在最后完成。

最佳答案

您看到的行为特定于 ArrayListSpliterator,它由 StreamArrayList 上使用。

代码中的注释解释了实现选择:

We perform only a single ConcurrentModificationException check at the end of forEach (the most performance-sensitive method) [JDK 8 source code]

这与并发修改检查的约定一致。在修改的情况下,迭代器不需要快速失败。如果他们确实选择快速失败,则实现者可以决定实现检查的严格程度。例如,如上所述,通常需要在正确性和性能之间进行权衡。

This exception may be thrown by methods that have detected concurrent modification of an object. [...] Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs. [Java SE 8 API docs]

关于Java 流 forEach concurrentModificationException 异常行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50987911/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com