当我运行以下代码时
打印捕获预期的ConcurrentModificationException
是预期的,但奇怪的是第二次迭代没有异常被捕获
无法捕获预期的ConcurrentModificationException
已打印。我真的不确定为什么第二次它没有被抓住。
public class TestLHS {
public static void main(String[] args) {
LinkedHashSet<Integer> lhSet = new LinkedHashSet<Integer>();
Integer one = new Integer(1);
Integer two = new Integer(2);
Integer three = new Integer(3);
Integer four = new Integer(4);
Integer cinco = new Integer(5);
// Add the three objects to the LinkedHashSet.
// By its nature, the LinkedHashSet will iterate in
// order of insertion.
lhSet.add(one);
lhSet.add(two);
lhSet.add(three);
// 1. Iterate over set. try to insert while processing the
// second item. This should throw a ConcurrentModificationEx
try {
for (Iterator<Integer> it = lhSet.iterator(); it.hasNext();) {
Integer num = (Integer) it.next();
if (num == two) {
lhSet.add(four);
}
System.out.println(num);
}
} catch (ConcurrentModificationException ex) {
System.out.println("Caught expected ConcurrentModificationException");
}
// 2. Iterate again, this time inserting on the (old) 'last'
// element. This too should throw a ConcurrentModificationEx.
// But it doesn't.
try {
for (Iterator<Integer> it = lhSet.iterator(); it.hasNext();) {
Integer num = (Integer) it.next();
if (num == four) {
lhSet.add(cinco);
}
System.out.println(num);
}
System.out.println("Failed to catch expected ConcurrentModificationException");
} catch (ConcurrentModificationException ex) {
System.out.println("Caught expected ConcurrentModificationException");
}
}
}
有人可以解释这种行为吗?
答案 0 :(得分:1)
如果查看LinkedHashMap的代码(或任何实现Iterator的类),您将看到在next()方法中检查了ConcurrentModificationException。
你在第一个for循环中得到ConcurrentModificationException,因为你添加了&#39; num&#39; ==&#39;两个&#39 ;;迭代器仍然有三个&#39;离开,所以循环继续。随后对next()的调用是抛出异常的地方。
在第二个循环中,您在迭代最后一个当前元素时添加,因此您不会调用next()并且不会抛出ConcurrentModificationException。
答案 1 :(得分:1)
让我们看一下tutorial:
如果在创建迭代器之后的任何时候修改了set,除了通过迭代器自己的
remove
方法之外,迭代器将抛出ConcurrentModificationException
。
请注意,不清楚哪个迭代器方法会抛出异常。我们来查看documentation:
public final boolean hasNext() {
return next != null;
}
// called by LinkedKeyIterator.next()
final LinkedHashMap.Entry<K,V> nextNode() {
LinkedHashMap.Entry<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
current = e;
next = e.after;
return e;
}
如您所见,next()
方法抛出了异常,而不是hasNext()
抛出异常。由于four
是集合中的最后一个元素,next
已经为空,因此对hasNext()
的下一次调用将返回false,并且不会再次调用next()
。因此,没有观察到并发修改,也没有抛出异常。
另见source
答案 2 :(得分:1)
这是一个已知的问题,编号 6258302 ,发布在JDK bugList。同样可以找到here
答案 3 :(得分:0)
Java Docs:
中明确提到了这一点但─ 此异常并不总是表示某个对象已被另一个线程同时修改。如果单个线程发出违反对象合同的一系列方法调用,则该对象可能会抛出此异常。例如,如果一个线程在使用失败快速迭代器迭代集合时直接修改集合,则迭代器将抛出此异常
注意: - 无法保证快速失败的行为,因为一般来说,在存在不同步的并发修改时,不可能做出任何硬性保证。失败快速操作会尽最大努力抛出 ConcurrentModificationException 。 因此,
: - 编写一个依赖于此异常的程序以确保其正确性是错误的:ConcurrentModificationException仅用于检测错误。
更多详情请参阅 - https://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html