【问题标题】:Why does Java have to throw a Concurrent Modification Exception? [closed]为什么 Java 必须抛出并发修改异常? [关闭]
【发布时间】:2013-05-11 14:40:30
【问题描述】:

我想了解 Java 的迭代器。为什么它们被设计为抛出并发修改异常?在 C++ STL 中,您可以迭代容器并随时修改内容,但为什么不能在 Java 中进行呢?

编辑:更正的问题。构图不正确。

【问题讨论】:

  • 它与多线程无关。修改底层集合会使迭代失效。
  • 此异常不一定只在两个线程参与修改对象时发生。 JAVADOC
  • 而且他们没有做任何事情来防止并发修改
  • 不一定是在多线程代码中抛出的。当您在迭代时修改集合时会发生这种情况。即使在单线程应用程序中也可能出现此异常。
  • 你从哪里得到迭代器线程化的想法?你的整个假设是一个很大的非事实陈述......

标签: java c++ exception iterator


【解决方案1】:

这是一个为什么迭代器在迭代列表时尝试修改列表时抛出的示例。

假设您的迭代器是使用索引实现的,如在ArrayList 中:假设您的迭代器现在指向List 中的位置3。现在您在位置1 添加一个元素。迭代器不知道你做了什么改变,所以它仍然指向位置 3,但是位置 3 现在保存了曾经在位置 2 的元素,因为一切都被向下移动了。所以你的迭代器现在将访问一个元素两次!这很糟糕。

因此规则是,当您在迭代列表时修改列表时,您必须从迭代器本身这样做,因此迭代器知道如何使其位置与对列表的修改保持同步。如果您在不通过迭代器的情况下修改列表,则迭代器会抛出 ConcurrentModificationException 而不是静默地损坏,例如多次访问一个元素。

【讨论】:

  • 但这如何回答 OP 关于能够用 C++ 而不是 Java 的问题?我认为在答案中注明它是有意义的!
【解决方案2】:

您可以在迭代集合时对其进行修改。您只需使用Iterator.remove() 即可。

ConcurrentModificationException 可能会被抛出,例如,如果另一个线程在迭代期间修改了集合。这比未定义的行为更可取。

Java 迭代器不是线程化的。可能存在多个线程,迭代器可能在这些线程中表现良好。

【讨论】:

    【解决方案3】:

    我不会解释为什么要这样设计它们,我只想告诉你这个小秘密:

    如果您在迭代期间从列表中删除,您将得到一个并发异常。 如果您在迭代期间删除使用迭代器,您可能会因为某些其他原因获得并发异常。

    类似的东西

    for(Iterator<?> iter = list.getIterator(); iter.hasNext(); )
    { 
       MyClass c = iter.getNext();
       if( //i need to remove this instance)
          iter.remove(iter);
    }
    

    将调用包装在synchronized 中或将变量标记为volatile 可能会帮助您避免并发修改,因为这些会同步对对象的访问,从而防止您同时从多个来源访问它。

    或使用 [COW 列表] (http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html)

    我今天似乎无法掌握如何在 SO 上链接内容....

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-15
      • 2013-09-16
      • 1970-01-01
      相关资源
      最近更新 更多