Java-使用经典的for循环时会发生并发修改异常吗?

时间:2019-02-27 06:14:26

标签: java collections exception-handling fail-fast

使用经典for循环时是否有机会发生并发修改异常?

import java.util.*;

class IterTest{
    public static void main(String[] args){
        List<Integer> nums = new ArrayList<>();
        nums.add(18);
        nums.add(1);
        nums.add(14);
        nums.add(13);
        System.out.println("Nums ->"+nums);
        int len = nums.size();
        for(int index=0;index < len ;index++){          
            System.out.println(" Current >>"+nums.get(index));
            System.out.println(" Removing >>"+nums.remove(index));          
        }
    }
}

3 个答案:

答案 0 :(得分:2)

不,没有机会。使用迭代器时可能会发生并发修改异常,请参见What are fail-safe and fail-fast iterators in java

答案 1 :(得分:2)

否,此代码不会给出ConcurrentModificationException。当集合视图从其下面更改而“破坏”集合视图时,通常会发生该异常。典型的示例是在Iterator(在for-for语句中隐式使用)进行迭代的同时修改集合,或者通过获取subList(),修改基础列表,然后继续使用子列表。

但是,此代码将以与“欺骗”循环相同的条件运行,只是会引发不同的异常。循环边界基于列表的初始大小。但是,循环体从列表中删除了元素,因此代码最终将在列表的边界之外建立索引,从而产生IndexOutOfBoundsException

如何修复此代码取决于您要执行的操作。最初似乎最好通过使用列表索引而不是ConcurrentModificationException来避免使用Iterator。但是,如果在循环过程中对列表进行结构上的修改(即添加或删除了元素),则需要仔细调整索引和循环边界,否则可能会跳过,重复元素或发生IndexOutOfBoundsException

答案 2 :(得分:0)

否,正如其他答案所建议的那样,在给定的代码中不会出现ConcurrentModificationException

那么什么时候发生ConcurrentModificationException?

在单线程环境中,通常会在使用Iterators遍历集合并同时对其进行修改时发生。

为什么?

如果您检查Iterator实现的源代码,则无论何时使用iterator的任何方法(例如next(),remove()),它始终会执行checkForComodification()。例如,在ArrayList.java中该方法的代码为:

final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

其中 modCount 是在ArrayList类级别维护的静态变量,表示该列表在结构上被修改的次数。 预期的修改计数 expectedModCount ,在Iterator类级别上维护,该级别最初等于modCount。

因此,只要预期的修改数量与实际进行的修改不匹配,就会出现异常。

在您的情况下,您没有使用过任何一种,因此不会检查共同修改,因此您将不会获得ConcurrentModificationException

注意:this answer中所述,由于在for循环中检查了IndexOutOfBoundsException,并且index < len被初始化为数组的初始大小,您将得到len。 一个简单的解决方案是:

 for(int index=0;index < nums.size;index++)