众所周知,我们不能在迭代它时修改非线程安全的集合,因为它会抛出一个ConcurrentModificationException
但我想知道的是,如果它不会抛出异常并让迭代和修改同时发生会发生什么。
例如,在迭代时从HashMap中删除一个元素。
删除。由于删除操作不会改变HashMap中基础表的长度,我认为这不是迭代的问题。
把。也许问题只发生在Put触发器调整大小()时,因为基础表将被洗牌。
我的分析是否正确?
答案 0 :(得分:5)
简答:不,你的分析不正确。
如果你在迭代它时(不使用迭代器)从集合中删除了某些东西,迭代器就没有很好的方法来跟踪它的位置。使用更简单的示例:List。假设迭代器位于索引10处,并删除索引5.该删除会移动所有索引。现在你在迭代器上调用next(),你......什么?转到索引11?保持在10指数?迭代器无法知道。
类似地,如果你在对它进行迭代时添加一些东西(不使用迭代器),迭代器也不知道它是在当前索引之前还是之后添加的,所以下一个()函数被破坏。
这甚至不会进入迭代器顺序取决于集合中的内容的数据结构,但问题类似于我上面列出的问题。
答案 1 :(得分:2)
但我想知道的是,如果它不会抛出异常并让迭代和修改同时发生会发生什么。
这是假设的,因为相应的(非并发)收藏品不会以这种方式工作。如果我们假设他们确实允许"并发"修改,那么我们仍然无法回答如何实现迭代的假设。最后,假设我们刚刚删除了快速失败测试,那么行为将是特定于集合的。
查看对HashMap案例的分析,您必须考虑迭代器对象的内部状态。我没有看过任何具体的实现代码,但是一个典型的HashMap迭代器将在主哈希数组中有一个哈希链的索引,以及一个指向哈希链中的节点的指针:
Map.remove不会改变散列图大小,因此链索引不会失效。但是,如果删除了错误的条目,我们可以发现迭代器的节点指针可以引用不再在链中的节点。这可能导致迭代返回已删除的地图条目。
您是正确的,触发调整大小的Map.put可能导致重新分配条目。这可能会导致某些条目被跳过,而其他条目将被退回两次。
答案 2 :(得分:0)
通常java.util
包中的传统集合类使用int变量(modCount
)来跟踪修改(添加和删除)。
当我们从这些集合类中请求Iterator
时,返回的Iterator
对象将提供现有的修改计数变量作为其预期的修改计数。
在调用next()
方法时,Iterator对象会根据其预期的修改计数值检查当前修改计数变量值。
如果不匹配,则ConcurrentModificationException
包中存在java.util
,其RuntimeException
为var configValues = getUserAgentValues();
var browserName = configValues.browser_name ;
var browserVersion = configValues.browser_vers;
var OSVersion = configValues.platform_type;
。
不要混淆集合对象的大小(如问题Map中所示)和可用的总桶数。此外,它与大小无关,一次添加会增加修改计数标志的值,并且删除也会增加其值。