Java-synchronized ArrayList仍然是ConcurrentModificationException
我得到了一个Java-synchronized ArrayList仍然是ConcurrentModificationException,java,arraylist,synchronized,Java,Arraylist,Synchronized,我得到了一个final ArrayList routingTable=new ArrayList()可多次访问。 但我只在一个点上得到一个ConcurrentModificationException,它位于以下线程中: Thread checkReplies = new Thread(() -> { while (true) { synchronized (routingTable) { for (RoutingTableEntry
final ArrayList routingTable=new ArrayList()代码>可多次访问。
但我只在一个点上得到一个ConcurrentModificationException
,它位于以下线程中:
Thread checkReplies = new Thread(() -> {
while (true) {
synchronized (routingTable) {
for (RoutingTableEntry entry : routingTable) { // throws it here
// do smth
}
}
// [...]
}
});
checkReplies.start();
即使routingTable
已经同步,它也会在循环中抛出异常。每个类只执行一次此线程
有什么想法吗?有两种可能性:
类中有修改路由表的其他代码,执行此操作时不使用同步(路由表)
。因此,当其他代码在迭代过程中修改列表时,您会得到错误
您正在修改注释为“do smth”的列表。仅仅因为您已经同步了列表,这并不意味着您可以在循环使用其迭代器时对其进行修改。您不能(除了通过迭代器本身,这意味着您不能使用增强的for
循环)。(有时,由于ArrayList
实现的细节,您可以侥幸逃脱,但有时则无法逃脱。)
下面是#2()的一个示例:
(还有add
和set
操作。)ConcurrentModificationException
在线程化的意义上不一定是“并发的”,它可以是“并发的”,即在迭代集合的同时不应直接修改集合
很长一段时间以来,它也存在于文档中(摘自Java7:)
请注意,此异常并不总是表示对象已被其他线程并发修改。如果单个线程发出一系列违反对象约定的方法调用,该对象可能会引发此异常例如,如果线程在使用fail fast迭代器迭代集合时直接修改集合,迭代器将抛出此异常。
而for(x:y)
使用了一个迭代器,它很容易成为一个“快速失败”迭代器。从您在原始问题中的评论开始,您在进行迭代时正在删除路由表中的项目
您无法执行此操作(如果路由表已同步,也可以执行此操作)
您是否在<代码>周期的<代码>中添加/删除<代码>路由表<代码>中的项目?是否有特殊原因使您不使用<代码>集合。synchronizedList()
或CopyOnWriteArrayList
?@Joe迭代集合。synchronizedList
与迭代同步块中的列表不同。@GabrieleMariotti我调用一个方法,该方法将删除(我是否应该使该方法同步?@Stefanxyz这就是问题所在。你做不到。我不太清楚你说“你做不到(除了…)”是什么意思。您是否忘记完成句子,或者您不能更改synchronized语句中列表的任何内容?@Stefanxyz-句子已完成,有一些修改方法可以在迭代过程中安全使用。但是,要使用它们,您必须显式地使用listIterator
和标准for
或而或类似的循环,您不能使用增强的for
循环(因为它对您隐藏了迭代器)。另请参阅我对答案的补充:您将两件基本上不相关的事情(同步和并发修改)混为一谈。谢谢您的回答。多亏了加布里埃尔·马里奥蒂和特维马达尔,我已经意识到了这一点。我将该结构修改为一个正常的“for”循环,这使得它成为可能(通过列表更改减少索引),感谢我实际上认为它是并发的(@tevemadar提到了它),现在它变得有意义了。
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");
}
}
}
for (var it = routingTable.listIterator(); it.hasNext; ) {
var entry = it.next();
if (/*...some condition...*/) {
it.remove(); // Removes the current entry
}
}
for (RoutingTableEntry entry : routingTable) { // throws it here
// routingTable.remove(....);
}