有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java ConcurrentModificationException和多个catch块

当我运行以下代码时

Caught expected ConcurrentModificationException

是打印出来的,这是意料之中的,但奇怪的事情是在第二次迭代中,并没有发现任何异常

Failed to catch expected 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");
        }

    }
}

有人能解释这种行为吗


共 (4) 个答案

  1. # 1 楼答案

    这是一个编号为6258302的已知问题,发布在JDK错误列表上。在here中也可以找到同样的结果

  2. # 2 楼答案

    如果查看LinkedHashMap(或任何实现迭代器的类)的代码,您将看到ConcurrentModificationException在next()方法中被选中

    在第一个for循环中得到ConcurrentModificationException,因为当'num'='two'时添加;迭代器还剩下“三个”,所以循环继续。对next()的后续调用是引发异常的地方

    在第二个循环中,当最后一个当前元素被迭代时添加,因此不调用next(),也不会抛出ConcurrentModificationException

  3. # 3 楼答案

    这一点在Java文档中有明确提到:-

    那- 此异常并不总是表示对象已被其他线程同时修改。如果单个线程发出一系列违反对象约定的方法调用,该对象可能会引发此异常。例如,如果线程在使用fail fast迭代器迭代集合时直接修改集合,迭代器将抛出此异常

    注意:-不能保证快速失效行为,因为一般来说,在存在非同步并发修改的情况下,不可能做出任何硬保证。Fail fast operations尽最大努力抛出ConcurrentModificationException。 所以

    :-编写依赖于此异常的正确性的程序是错误的:ConcurrentModificationException应该只用于检测错误

    更多详细信息请参阅-https://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html

  4. # 4 楼答案

    让我们看看documentation

    if the set is modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException.

    请注意,哪个迭代器方法将引发异常并不明确。让我们检查一下source

    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()。因此,不会观察到并发修改,也不会引发异常

    另见Why isn't this code causing a ConcurrentModificationException?