《Java 并发实践》提到:
The iterator returned by the
ConcurrentHashMap
are weakly consistent than fail-fast. A weakly consistent iterator can tolerate the concurrent modifications, traverses elements as they existed when the iterator was constructed, and may (but is not guaranteed to) reflect modifications to the collection after the construction of the iterator.
- 如何使迭代器弱一致或故障安全在并发环境中有所帮助,因为
ConcurrentHashMap
的状态仍然会被修改。唯一的问题是它不会抛出ConcurrentModificationException
。 - 为什么在创建故障安全迭代器时集合返回故障快速迭代器有利于并发。
最佳答案
您的具体情况的正确性
请记住,快速失败迭代器会迭代原始集合。
相反,故障安全(又名弱一致)迭代器迭代原始集合的副本。因此,对原始集合的任何更改都不会被注意到,这就是它保证不存在 ConcurrentModificationException
的方式。
回答您的问题:
- 使用故障安全迭代器有助于并发,因为您不必阻塞整个集合的读取线程。阅读时可以在下面修改集合。缺点是读取线程会将集合的状态视为创建迭代器时拍摄的快照。
- 如果上述限制不适合您的特定用例(您的读者应该始终看到集合的相同状态),您必须使用快速失败迭代器并保持对集合的并发访问控制得更严密。
正如您所看到的,这是用例的正确性和速度之间的权衡。
并发 HashMap
ConcurrentHashMap
(CHM) 利用多种技巧来提高访问的并发性。
- 首先CHM实际上是多个 map 的分组;每个
MapEntry
都存储在多个段之一中,每个段本身都是一个可以同时读取的哈希表(read
方法不会阻塞)。 - 段的数量是 3 参数构造函数中的最后一个参数,称为
concurrencyLevel
(默认16)。段的数量决定了整个数据中并发写入的数量。额外的内部哈希算法确保了段之间条目的均匀分布。 - 每个
HashMapEntry
的值都是volatile
,从而确保争用修改和后续读取的细粒度一致性;每次读取都会反射(reflect)最近完成的更新 - 迭代器和枚举是故障安全 - 反射(reflect)自迭代器/枚举创建以来某个时刻的状态;这允许同时读取和修改,但代价是降低了一致性。
关于java - ConcurrentHashMap 的弱一致迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36079344/