【问题标题】:ConcurrentHashMap returns a weakly consistent iterator, why should we use it anyhow?ConcurrentHashMap 返回一个弱一致的迭代器,我们为什么要使用它呢?
【发布时间】:2012-12-29 17:22:48
【问题描述】:

我在实践中阅读 Java Concurrecny 一书。在第 85 页第 5.2.1 节中,它讨论了 ConcurrentHashMap 及其优势。然而,在一方面,这些书声称

ConcurrentHashMap 返回的迭代器是弱一致的。这 意味着这个迭代器可以容忍并发修改, 遍历构造迭代器时存在的元素,并且 可能(但不保证)反映对集合的修改 在迭代器构建之后。

为什么我理解并发程序中同步的全部意义在于允许线程以一致的方式访问共享资源,而 ConcurrentHashMap 并没有真正实现这一点。那为什么要使用它呢?

【问题讨论】:

    标签: java concurrency concurrent-programming concurrenthashmap


    【解决方案1】:

    关键是在不需要时避免同步。如果您不介意在某些情况下看到新元素而在其他情况下看不到它们,那么使用ConcurrentHashMap 的迭代器可能比在您迭代时防止其他线程添加项目要便宜得多either 在创建迭代器时拍摄一致的快照。

    所以是的,当您需要同步和一致的迭代器时,您将需要一个替代方案 - 但当您不需要时,您可以利用ConcurrentHashMap 提供的更高效的迭代器。

    【讨论】:

    • ConcurrentHashMap 在其实现中本身是否有同步?
    • @Hossein:我不知道 - 但您可以尽可能轻松地查看源代码 :) 文档建议在写入访问中可能存在同步但不读取:“但是,即使尽管所有操作都是线程安全的,但检索操作不需要锁定,并且不支持以阻止所有访问的方式锁定整个表。”
    • @Hossein:IIRC ConcurrentHashMap 是无锁实现,因此它没有传统意义上的同步,而是使用原子和特殊算法来避免互斥锁。它使它更快,因为互斥锁在某些应用程序中可能过于重量级(撇开它本身的成本,它一次只允许运行 1 个线程)但它没有完全同步。
    • @Maciej:ConcurrentHashMap 是锁条带实现,默认并发级别为 16。
    • @PrinceJohnWesley: Ups。抱歉 - 我的错(我看到 ConcurrentHashMap 阅读 ConcurrentSkipListMap)。
    【解决方案2】:

    ConcurrentHashMap 按照约定应该是线程安全的。但是,它不应该跨线程保持一致

    当您迭代 ConcurrentHashMap 时,迭代器会在您请求时获取哈希映射的副本(并且副本是以线程安全的方式制作的)并且您遍历该副本。是的,没有什么可以保证您在迭代该副本时,某些映射条目不会被删除。但是将以这种方式删除的地图条目仍然存在于您的迭代器中

    【讨论】:

    • 这样的条目可能不会存在于迭代器中。
    • 不,“会”。如果它是“可能”但它没有,你会得到一个ConcurrentModificationException
    • 来自 Java SDK 文档“它们不会抛出 ConcurrentModificationException`。”。
    • 是的,因为在复制时,给定哈希桶的所有条目都被复制了——但在您迭代时它们可能会从映射中删除。
    • IteratorConcurrentHashMap 不适用于副本。它可能会返回在创建 Iterator 之后添加的条目,甚至在您已经从它接收到一些元素之后。我已经尝试过了,有时会在现实中发生(Java 8)。否则它不会是weakly一致的。
    【解决方案3】:

    一切都取决于您需要多强的一致性。如果您需要强大的功能 - 互斥锁或其他操作子集将提供您所需要的。

    但有时您需要更弱的要求,但例如您需要说无锁属性,因为您需要保证吞吐量。另一方面,您可能根本不需要迭代器,或者对它们的限制要弱得多。

    因此,如果您只需要跨线程共享地图ConcurrentHashMap(例如在剧院中预订的人)将提供您需要的东西 - 如果您有许多工作线程,因为您避免互斥同步,它可能会更快。另一方面,速度是有代价的——迭代器提供的视图不一定对应于它创建时的集合状态,它可能会错过一些创建后记的元素(通常在多处理器系统中happens-before 关系很棘手)。

    编辑:正如约翰卫斯理王子指出的那样,我在看和写的时候想到了ConcurrentSkipListMapConcurrentHashMap。除了关于无锁的部分(以及由此产生的所有内容,如保证吞吐量等)之外,大多数观点仍然有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-29
      • 2017-03-19
      • 1970-01-01
      • 2010-09-15
      • 2021-07-11
      • 2021-08-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多