为什么会出现 ConcurrentModificationException?
Why do I get a ConcurrentModificationException?
为什么我在代码的指定位置得到了一个 ConcurrentModificationException?我无法弄清楚我做错了什么... removeMin()
方法用于在列表 pq
中找到最小值,将其删除,然后 return 它的值
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;
}
}
您遇到问题是因为您在为 pq
创建了一个迭代器之后使用正常的 .add()
方法向 pq
添加了项目。当您执行 hasNext()
时,迭代器不会抱怨,因为它看到了 pq
.
中的变化
while (itPQ.hasNext()) {
...
Integer element = itPQ.next(); --> you get exception here
...
}
但是,当您尝试遍历 pq
时,它会抛出异常。根据这个post,"If the iterator detects that some modifications were made without using its method (or using another iterator on the same collection), it cannot guarantee anymore that it will not pass twice on the same element or skip one, so it throws this exception."
我运行你的代码,结果发现违规行在这里:
Iterator<Integer> itPQ = pq.iterator();
这需要在 你的人口 pq
之后出现,这样迭代器就不会异步更新它的数据。
通过此修改代码 运行s.
现在,它不 运行 正确。原因正如@Ishnark 在他的回答中指出的那样,每次您从列表中删除时,它都会变小,因此并非所有列表都被添加到 pq
.
一旦从中获取迭代器的集合被修改,迭代器就不应被视为可用。 (此限制放宽 java.util.concurrent.* 集合 类。)
您首先获取 pq
的迭代器,然后修改 pq
。一旦你修改 pq
,迭代器 itPQ
就不再有效,所以当你尝试使用它时,你会得到一个 ConcurrentModificationException。
一个解决方案是将 Iterator<Integer> itPQ = pq.iterator();
移到 while
循环之前。更好的方法是完全取消对 Iterator 的显式使用:
for (Integer element : pq) {
从技术上讲,for-each 循环在内部使用迭代器,因此无论哪种方式,只要您不尝试在循环内修改 pq
,此循环才有效。
为什么我在代码的指定位置得到了一个 ConcurrentModificationException?我无法弄清楚我做错了什么... removeMin()
方法用于在列表 pq
中找到最小值,将其删除,然后 return 它的值
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;
}
}
您遇到问题是因为您在为 pq
创建了一个迭代器之后使用正常的 .add()
方法向 pq
添加了项目。当您执行 hasNext()
时,迭代器不会抱怨,因为它看到了 pq
.
while (itPQ.hasNext()) {
...
Integer element = itPQ.next(); --> you get exception here
...
}
但是,当您尝试遍历 pq
时,它会抛出异常。根据这个post,"If the iterator detects that some modifications were made without using its method (or using another iterator on the same collection), it cannot guarantee anymore that it will not pass twice on the same element or skip one, so it throws this exception."
我运行你的代码,结果发现违规行在这里:
Iterator<Integer> itPQ = pq.iterator();
这需要在 你的人口 pq
之后出现,这样迭代器就不会异步更新它的数据。
通过此修改代码 运行s.
现在,它不 运行 正确。原因正如@Ishnark 在他的回答中指出的那样,每次您从列表中删除时,它都会变小,因此并非所有列表都被添加到 pq
.
一旦从中获取迭代器的集合被修改,迭代器就不应被视为可用。 (此限制放宽 java.util.concurrent.* 集合 类。)
您首先获取 pq
的迭代器,然后修改 pq
。一旦你修改 pq
,迭代器 itPQ
就不再有效,所以当你尝试使用它时,你会得到一个 ConcurrentModificationException。
一个解决方案是将 Iterator<Integer> itPQ = pq.iterator();
移到 while
循环之前。更好的方法是完全取消对 Iterator 的显式使用:
for (Integer element : pq) {
从技术上讲,for-each 循环在内部使用迭代器,因此无论哪种方式,只要您不尝试在循环内修改 pq
,此循环才有效。