为什么Java必须抛出并发修改异常?

时间:2013-05-16 15:43:56

标签: java c++ exception iterator

我想知道Java的迭代器。为什么它们被设计为抛出并发修改异常?在C ++ STL中,您可以遍历容器并随意修改内容,但为什么不能在Java中执行此操作?

编辑:更正了问题。框架不正确。

3 个答案:

答案 0 :(得分:5)

以下是为什么迭代器在您迭代时尝试修改列表时会抛出的示例。

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

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

答案 1 :(得分:3)

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

例如,如果另一个线程在迭代期间修改了集合,则可能抛出

ConcurrentModificationException。这比未定义的行为更可取。

Java迭代器没有线程化。可能存在多个线程,并且迭代器在这些中可能表现良好。

答案 2 :(得分:-1)

我不会解释他们为什么按照他们的方式设计,而是让你了解这个小秘密:

如果在迭代期间从列表中删除,则会出现并发异常。 如果在迭代期间使用迭代器删除,则可能由于其他原因而获得并发异常。

像这样的东西

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上链接内容....