有 Java 编程相关的问题?

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

java为什么在一个线程迭代(使用迭代器)而另一个线程修改同一个非线程安全ArrayList副本时没有ConcurrentModificationException

一些背景:
当使用Iterator迭代集合时,可能会出现java.util.ConcurrentModificationException,因为在创建Iterator对象时,会捕获集合或数组列表的修改计数(modCount),并在每次使用Iterator.next()迭代时检查modCount是否已更改,如果已更改,则抛出java.util.ConcurrentModificationException

关于创建迭代器对象(来自ArrayListIterator实现):
int expectedModCount = modCount;

下面的方法被调用Iterator.next(),它抛出异常(来自ArrayListIterator实现):

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

我可以用下面的代码很好地复制它:

List<String> stringList = new ArrayList<String>();
                stringList.add("a");
                stringList.add("b");
                stringList.add("c");
                Iterator<String> iterator = stringList.iterator();
                System.out.println("Got iterator object");
                while (iterator.hasNext()) {
                    String player = iterator.next();
                    player.toString();
                    System.out.println("UpperCase: " + player.toUpperCase());
                    iterator.remove();
                    stringList.add("a1"); //This is root cause of exception.
                }

问题:

  • 如果我尝试使用不同的线程(代码如下)修改列表,那么我不会得到java.util.ConcurrentModificationException,但是如果我使用相同的线程,那么我会得到异常

如果我理解正确,那么在第一个线程的Iterator.next()的每次传递中,Iterator.checkForComodification()都会在内部调用,因为我的第二个线程已经修改了列表,所以最新的modCount将不等于Iterator.expectedModCount,这是在创建Iterator对象时初始化的,因此Iterator.checkForComodification()应该发生异常。对吧

我已经验证了列表正在从线程2更新,线程1的迭代器能够打印新值,因为我可以看到第二个线程正在添加的“d”值

private static void iteratorException() {
    final List<String> stringList = new ArrayList<String>();

    Thread thread = new Thread(){
        @Override
        public void run() {
            System.out.println("T1");
            stringList.add("a");
            stringList.add("b");
            stringList.add("c");
            Iterator<String> iterator = stringList.iterator();
            System.out.println("Got iterator object");
            while (iterator.hasNext()) {
                String player = iterator.next();
                player.toString();
                System.out.println("UpperCase: " + player.toUpperCase());
                iterator.remove();
                //stringList.add("a1");
            }
        }
    };

    Thread thread2 = new Thread(){
        @Override
        public void run() {
            System.out.println("T2");
            stringList.add("d");
            stringList.remove("a");
            System.out.println("finished T2");
        }
    };

    thread.start();
    thread2.start();
}

共 (0) 个答案