简体   繁体   English

如果在迭代时修改集合而不抛出 ConcurrentModificationException 会发生什么

[英]what will happen if modify a collection while iterating without throwing the ConcurrentModificationException

As all known We can't modify a non-thread-safe collection while iterating it since it will throw a ConcurrentModificationException众所周知,我们不能在迭代时修改非线程安全的集合,因为它会抛出 ConcurrentModificationException

But what I want to know is that what will happen if it would not throw a Exception and let the iteration and modification happened concurrently.但是我想知道的是,如果它不抛出异常并让迭代和修改同时发生会发生什么。

For example, remove an element from a HashMap while iterating it.例如,在迭代时从 HashMap 中删除一个元素。

  1. Remove.消除。 Since remove operation would not change the length of the underlying table in the HashMap, I think that's not an issue to the iteration.由于remove操作不会改变HashMap中底层表的长度,我认为这不是迭代的问题。

  2. Put.放。 Maybe problem only occurs when the Put triggers resize() since the underlying table will be shuffled.也许问题仅在 Put 触发 resize() 时发生,因为基础表将被洗牌。

Is my analysis correct?我的分析正确吗?

Short answer: no, your analysis is not correct.简短回答:不,您的分析不正确。

If you remove something from a collection while you're iterating over it (without using the iterator), the iterator doesn't have a good way to keep track of where it is.如果在迭代集合时从集合中删除某些内容(不使用迭代器),则迭代器没有很好的方法来跟踪它的位置。 Use a simpler example: List.使用更简单的示例:列表。 Say the iterator is at index 10, and you remove index 5. That removal shifts all of the indices.假设迭代器位于索引 10 处,然后删除索引 5。该删除会移动所有索引。 Now you call next() on the iterator, and you.. what?现在你在迭代器上调用 next() ,你..什么? Go to index 11?转到索引 11? Stay at index 10?保持指数 10? The iterator has no way to know.迭代器无法知道。

Similarly, if you add something to a collection while you're iterating over it (without using the iterator), the iterator doesn't know if that was added before or after the current index, so the next() function is broken.类似地,如果在迭代集合时向集合添加某些内容(不使用迭代器),迭代器不知道它是在当前索引之前还是之后添加的,因此 next() 函数被破坏。

This doesn't even get into data structures where the iterator order depends on what's in the collection, but the issues are similar to the ones I listed above.这甚至没有涉及迭代器顺序取决于集合中的内容的数据结构,但问题与我上面列出的问题类似。

But what I want to know is that what will happen if it would not throw a Exception and let the iteration and modification happened concurrently.但是我想知道的是,如果它不抛出异常并让迭代和修改同时发生会发生什么。

This is hypothetical because the respective (non-concurrent) collections don't work that way.这是假设性的,因为相应的(非并发)集合不是这样工作的。 If we hypothesize that they did allow "concurrent" modification, then we still cannot answer without making assumptions about how iteration would then be implemented.如果我们假设它们确实允许“并发”修改,那么我们仍然无法在不假设如何实现迭代的情况下回答。 Finally, assuming that we just removed the fast-fail tests, then the behaviour will be collection specific.最后,假设我们刚刚删除了快速失败测试,​​那么行为将是特定于集合的。

Looking at your analysis for the HashMap case, you have to consider the internal state of the iterator object.查看您对 HashMap 案例的分析,您必须考虑迭代器对象的内部状态。 I haven't looked at any specific implementation code, but a typical HashMap iterator will have an index for a hash chain in the main hash array, and a pointer to a node within the hash chain:我没有看过任何具体的实现代码,但是典型的 HashMap 迭代器将在主散列数组中具有一个散列链的索引,以及一个指向散列链中节点的指针:

  • A Map.remove won't change the hashmap size, so the chain index won't be invalidated. Map.remove 不会更改哈希图大小,因此链索引不会失效。 However, if the wrong entry was removed, we could find that the iterator's node pointer could refer to a node that is no longer in the chain.但是,如果删除了错误的条目,我们会发现迭代器的节点指针可能指向链中不再存在的节点。 This could cause the iteration to return deleted map entries.这可能会导致迭代返回已删除的地图条目。

  • You are correct that a Map.put that triggered a resize could cause the entries to be redistributed.您是正确的,触发调整大小的 Map.put 可能导致条目被重新分配。 This could cause some entries to be skipped, and others to be returned twice.这可能会导致跳过某些条目,而其他条目会返回两次。

Usually the traditional collection classes in java.util package uses an int variable ( modCount ) to keep track of modifications (additions and deletions).通常java.util包中的传统集合类使用一个 int 变量 ( modCount ) 来跟踪修改(添加和删除)。

When we ask for an Iterator from these collection classes then a object of Iterator which is returned is provided with the existing modification count variable as its expected modification count.当我们从这些集合类中请求一个Iterator ,返回的Iterator对象将提供现有的修改计数变量作为其预期的修改计数。

Upon invoking the next() method the Iterator object checks the current modification count variable value against its expected modification count value.在调用next()方法时,Iterator 对象根据其预期的修改计数值检查当前修改计数变量值。

In case of a mismatch it fails fast by throwing ConcurrentModificationException present in java.util package, its a RuntimeException .如果不匹配,它会通过抛出java.util包中存在的ConcurrentModificationException快速失败,它是一个RuntimeException

Do not get confused between the size of the collection object (as in your question Map) and the total buckets available.不要在集合对象的大小(如您的问题地图中)和可用的总存储桶之间混淆。 Moreover its not about the size, one addition increases the value of the modification count flag and also a deletion increases its value.此外,它与大小无关,添加一次会增加修改计数标志的值,而删除也会增加其值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 迭代此集合时如何避免ConcurrentModificationException? - How to avoid ConcurrentModificationException while iterating this collection? 如果我们在迭代时最后在ArrayList中添加元素,则抛出ConcurrentModificationException - Throwing ConcurrentModificationException if we add elements in ArrayList at the end while iterating 通过HashMap迭代时出现ConcurrentModificationException - ConcurrentModificationException while iterating through HashMap 遍历集合以添加项目但抛出 ConcurrentModificationException - Iterating through collections to add items but throwing ConcurrentModificationException 如何在没有ConcurrentModificationException的情况下修改subList? - How to modify subList without ConcurrentModificationException? Java 迭代集合在保存后抛出 ConcurrentModificationException - Java iterating collection throws ConcurrentModificationException after Save 您如何对收藏进行交互 <T> 并修改其没有ConcurrentModificationException的项目? - How do you interate over a Collection<T> and modify its items without ConcurrentModificationException? 遍历列表但未修改列表时发生ConcurrentModificationException - ConcurrentModificationException while iterating through a list but not modifying it 迭代Arraylist时的ConcurrentModificationException(不删除) - ConcurrentModificationException while iterating through Arraylist (not removing) 遍历List时发生ConcurrentModificationException,尽管未对其进行任何修改 - ConcurrentModificationException while iterating through List, altough not modifying it
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM