【问题标题】:Concurrenthashmap Iterator data structureConcurrenthashmap 迭代器数据结构
【发布时间】:2014-06-13 03:43:52
【问题描述】:

我需要询问 ConcurrentHashMap 的以下方面,因为我无法从源代码中弄清楚。
(请注意,我不是在问行为,这是很好理解的。它是关于迭代器用于显示行为的机制)

"The iterator is guaranteed to reflect the state of the map at the time of it's creation."

1.这是否意味着迭代器获得了自己的备份映射副本? 为什么即使在创建迭代器之后,易失性读取也不会给出“价值”的真实状态? (代码的确切位置将不胜感激)

2. 非阻塞读取和迭代如何设法保持一致,即使是在一个段正在进行重新散列时?

【问题讨论】:

  • 好吧,如果一个段正在重新散列,这意味着映射在结构上被修改了,并且根据 javadoc 迭代器没有必须反映修改后的修改被创造。如果他们这样做,我不知道他们是如何工作的。另外,我真的想说我以前见过类似的东西,但我不完全确定......
  • 你从哪里得到这个报价?我不相信 ConcurrentHashMap 的行为是“很好理解的”: ConcurrentHashMap 的迭代器弱一致 ... javadoc 指出:“迭代器和枚举返回反映哈希表状态的元素在创建迭代器/枚举时或之后的某个时间点”。

标签: java collections concurrenthashmap


【解决方案1】:

正如 cmets 中所述,我不相信 ConcurrentHashMap 的行为是“很好理解的”。您在未注明出处的报价中所作的断言对于 ConcurrentHashMap 是不正确的。

ConcurrentHashMap 的迭代器弱一致...javadoc 指出:

迭代器、拆分器和枚举返回反映哈希表状态的元素在迭代器/枚举创建时或之后的某个时间

鉴于此,

您的问题 1 的简短回答是:不,它没有自己的地图副本

对您的问题 2 的简短回答是:“表现始终如一”


以下是来自 javadocs 的一些其他相关引用,有助于解释实现:

基本策略是将表细分为Segments,每个Segment本身就是一个并发可读的哈希表……

段维护一个条目列表表,该表始终保持一致状态,因此可以在不锁定的情况下读取(通过段和表的易失性读取)。这需要在调整表大小时在必要时复制节点,因此仍然使用旧版本表的读者可以遍历旧列表。

节点复制在其 rehash 方法中针对每个 Segment 进行。 Segment.rehash() 方法的 javadocs 解释了该功能:

将每个列表中的节点重新分类为新表。因为我们使用的是二次幂展开,所以每个 bin 中的元素必须保持相同的索引,或者以二次幂的偏移量移动。我们通过捕获旧节点可以重用的情况来消除不必要的节点创建,因为它们的下一个字段不会改变。统计上,在默认阈值下,当表翻倍时,只有大约六分之一需要克隆。一旦它们不再被可能在并发遍历表中的任何读取器线程引用,它们替换的节点将被垃圾回收。条目访问使用普通数组索引,因为它们之后是易失性表写入。

请参阅Richard Burnison's excellent article 以获得对 jdk 7 的 ConcurrentHashMap 实现细节的全面描述。


更多信息:

Javadocs for ConcurrentHashMap jdk8

Source code for ConcurrentHashMap (openjdk-7)

ConcurrentHashMap returns a weakly consistent iterator, why should we use it anyhow?

【讨论】:

    猜你喜欢
    • 2016-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-22
    • 2013-10-12
    • 2017-08-25
    • 2014-01-28
    相关资源
    最近更新 更多