实际上,Java并发性提到:
ConcurrentHashMap返回的迭代器比失败快速迭代器具有弱的一致性。弱一致性迭代器可以容忍并发修改,遍历迭代器构造时存在的元素,并且可以(但不能保证)反映迭代器构造后对集合的修改。
ConcurrentHashMap的静止状态将被修改。唯一的问题是它不会抛出ConcurrentModificationException。发布于 2016-03-18 09:18:27
在特定情况下的正确性
请记住,失败快速迭代器迭代原来的集合。
相反,失败安全的(即弱一致的)迭代器在原始集合的副本上迭代。因此,对原始集合的任何更改都不会被注意到,这就是它如何保证缺少ConcurrentModificationException的原因。
回答你的问题:
正如您所看到的,这是在用例的正确性和速度之间的权衡。
ConcurrentHashMap
ConcurrentHashMap (CHM)利用多种技巧来提高访问的并发性。
MapEntry存储在一个段的数量中,本身就是一个可并发读取的哈希表(read方法不阻塞)。concurrencyLevel (默认16)。段数决定了整个数据中并发写入器的数量。通过附加的内部哈希算法,保证了条目在各段之间的均匀扩展。HashMapEntry的值都是volatile,从而确保了竞争修改和后续读取的细粒度一致性;每次读取都反映了最近完成的更新。发布于 2016-03-18 08:23:44
博士:因为锁。
如果您想要一个一致的迭代器,那么您必须将所有修改的锁定到Map --这在并发环境中是一个很大的损失。
当然,如果这是您想要的,您可以手动执行,但是迭代Map并不是它的目的,因此默认行为允许在迭代时并发写入。
相同的参数不适用于普通集合,这些集合只能(允许)由单个线程访问。ArrayList上的迭代应该是一致的,所以失败的快速迭代器会执行一致性。
发布于 2016-03-26 08:47:10
首先,并发集合的迭代器不是故障安全,因为它们没有能够以某种方式处理某种紧急过程的故障模式。他们不会失败的。
非并发集合的迭代器由于性能原因而失败,因为它们的设计方式不允许修改它们所遍历的集合的内部结构。例如,当hashmap被调整大小时,hashmap的迭代器将不知道如何在重组后继续迭代。
这意味着它们不仅会因为其他线程访问它们而失败,如果当前线程执行的修改使迭代器的假设无效,它们也会失败。
这些集合没有忽略那些麻烦的修改,而是返回不可预测和损坏的结果,而是尝试跟踪修改,并在迭代期间抛出异常,通知程序员某些地方出了问题。这叫做抗故障。
这些故障快速机制也不是线程安全的。这意味着,如果非法修改不是发生在当前线程,而是来自不同的线程,那么它们将不再被检测到。在这种情况下,它只能被认为是一种尽力而为的故障检测机制。
另一方面,并发集合的设计必须能够同时处理多次写入和读取,并且底层结构不断变化。
因此迭代器不能总是假设底层结构在迭代期间从未被修改过。
相反,它们的设计目的是提供较弱的保证,例如迭代过时的数据,或者还可能显示在创建迭代器之后发生的一些但不是所有的更新。这也意味着,当它们在单个线程中的迭代过程中被修改时,它们可能返回过时的数据,这对程序员来说可能有点违背直觉,因为人们通常期望在单个线程中立即看到修改。
示例:
HashMap:尽力而为的失败快速迭代器.
clear():保证在下一个迭代器步骤中抛出一个ConcurrentModificationExceptionCopyOnWriteArrayList:快照迭代器
clear()不会停止迭代ConcurrentSkipListMap:弱一致迭代器
clear()可能停止迭代,也可能不停止迭代,删除条目可能也可能不会阻止它们在剩余的迭代过程中出现。https://stackoverflow.com/questions/36079344
复制相似问题