为啥我会收到 ConcurrentModificationException?
Posted
技术标签:
【中文标题】为啥我会收到 ConcurrentModificationException?【英文标题】:Why do I get a ConcurrentModificationException?为什么我会收到 ConcurrentModificationException? 【发布时间】:2017-06-08 21:14:41 【问题描述】:为什么我会在代码中的指定位置收到 ConcurrentModificationException?我无法弄清楚我做错了什么... removeMin()
方法被用于在列表pq
中找到最小值,将其删除并返回其值
import java.util.Iterator;
import java.util.LinkedList;
public class test1
static LinkedList<Integer> list = new LinkedList<Integer>();
public static void main(String[] args)
list.add(10);
list.add(4);
list.add(12);
list.add(3);
list.add(7);
System.out.println(removeMin());
public static Integer removeMin()
LinkedList<Integer> pq = new LinkedList<Integer>();
Iterator<Integer> itPQ = pq.iterator();
// Put contents of list into pq
for (int i = 0; i < list.size(); i++)
pq.add(list.removeFirst());
int min = Integer.MAX_VALUE;
int pos = 0;
int remPos = 0;
while (itPQ.hasNext())
Integer element = itPQ.next(); // I get ConcurrentModificationException here
if (element < min)
min = element;
remPos = pos;
pos++;
pq.remove(remPos);
return remPos;
【问题讨论】:
我的猜测是,自从你创建了Iterator
之前你开始添加额外的元素迭代器突然在它的脚下更新了它的数据,可以这么说
【参考方案1】:
一旦从中获取迭代器的集合被修改,则不应将其视为可用。 (java.util.concurrent.* 集合类放宽了这个限制。)
您首先获取pq
的迭代器,然后修改pq
。一旦你修改了pq
,迭代器itPQ
就不再有效,所以当你尝试使用它时,你会得到一个ConcurrentModificationException。
一种解决方案是将Iterator<Integer> itPQ = pq.iterator();
移动到while
循环之前的右侧。更好的方法是完全取消对 Iterator 的显式使用:
for (Integer element : pq)
从技术上讲,for-each 循环在内部使用一个迭代器,因此无论哪种方式,只要您不尝试在循环内修改 pq
,此循环才有效。
【讨论】:
赞成 foreach 方法。我个人认为这更清洁 @VGR "你首先为 pq 获取一个迭代器,然后修改 pq"。这本身不是问题。问题是没有使用迭代器自己的 add 方法。将元素添加到pq
。如果使用 ListIterator 提供的 add 方法,迭代器可以毫无问题地遍历pq
。但我喜欢这个解决方案。
我同意上面的说法,我已经修改了我的代码,但是现在当我删除最小值时,它会出现 IndexOutOfBoundsException
@kprog 听起来像是一个不同的问题,应该作为一个新问题提出。【参考方案2】:
我运行了你的代码,结果发现有问题的行在这里:
Iterator<Integer> itPQ = pq.iterator();
这需要在您的pq
人口之后进行,以便迭代器不会异步更新其数据。
通过此修改,代码运行。
现在,它确实没有正常运行。原因正如@Ishnark 在他的回答中指出的那样,每次您从列表中删除时,它都会变小,因此并非所有列表都被添加到pq
。
【讨论】:
【参考方案3】:您遇到了一个问题,因为您在为pq
创建了一个迭代器之后,使用普通的.add()
方法向pq
添加了项目。当您执行 hasNext()
时,迭代器不会抱怨,因为它会看到 pq
的变化。
while (itPQ.hasNext())
...
Integer element = itPQ.next(); --> you get exception here
...
但是,当您尝试遍历 pq
时,它会引发异常。根据这个post,“如果迭代器检测到一些修改没有使用它的方法(或在同一个集合上使用另一个迭代器),它不能再保证它不会在同一个元素上传递两次或跳过一个,所以它会抛出这个异常。”
【讨论】:
虽然我同意这绝对是粗略的代码,但 OP 明确指出此处不会引发错误 这与list
无关。异常是由于获取itPQ
,然后修改pq
,然后尝试使用itPQ
。以上是关于为啥我会收到 ConcurrentModificationException?的主要内容,如果未能解决你的问题,请参考以下文章