gpt4 book ai didi

Java - 同步的 ArrayList 仍然是 ConcurrentModificationException

转载 作者:行者123 更新时间:2023-11-30 06:01:25 24 4
gpt4 key购买 nike

我得到一个 final ArrayList<RoutingTableEntry> routingTable = new ArrayList<>();被多次访问。但我只在一个点上得到一个 ConcurrentModificationException这是在以下线程中:

Thread checkReplies = new Thread(() -> {

while (true) {

synchronized (routingTable) {

for (RoutingTableEntry entry : routingTable) { // throws it here

// do smth
}
}

// [...]
}
});
checkReplies.start();

它在循环中抛出异常,即使 routingTable已经同步。该线程每个类(class)只执行一次。

有什么想法吗?

最佳答案

有两种可能:

  1. 您在修改 routingTable 的类中有其他代码,并且在这样做时没有使用synchronized (routingTable) .因此,当其他代码在该迭代期间修改列表时,您会收到错误。

  2. 您正在修改包含“do smth”评论的列表。仅仅因为您已同步列表,并不意味着您可以在使用其迭代器循环时修改它。你不能(除了通过迭代器本身,这意味着你不能使用增强的 for 循环)。 (有时您会因为 ArrayList 实现的细节而逃脱,但有时您不会。)

这是 #2 ( live copy ) 的示例:

var routingTable = new ArrayList<String>();
routingTable.add("one");
routingTable.add("two");
routingTable.add("three");
synchronized (routingTable) {
for (String entry : routingTable) {
if (entry.equals("two")) {
routingTable.add("four");
}
}
}

JDK12 的 ArrayList 实现失败了(至少,可能是其他的)。

需要理解的一个关键点是,在迭代过程中同步和修改列表在很大程度上是不相关的概念。同步(正确完成)可防止多个线程同时访问列表。但是正如您在上面的示例中所看到的,仅单个线程就可以通过在迭代期间修改列表来引发 ConcurrentModificationException。它们的唯一关系在于,如果您有一个线程读取列表而另一个线程可能修改它,则同步会在读取发生时阻止修改。除此之外,它们是无关的。

在您的评论中:

i call a method which removes then

如果您要删除循环的条目,您可以通过 list iterator 来完成的 remove方法:

for (var it = routingTable.listIterator(); it.hasNext; ) {
var entry = it.next();
if (/*...some condition...*/) {
it.remove(); // Removes the current entry
}
}

(还有addset操作。)

关于Java - 同步的 ArrayList 仍然是 ConcurrentModificationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57604375/

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