Java ConcurrentHashMap返回一个弱一致迭代器,我们为什么要使用它呢?

Java ConcurrentHashMap返回一个弱一致迭代器,我们为什么要使用它呢?,java,concurrency,concurrent-programming,concurrenthashmap,Java,Concurrency,Concurrent Programming,Concurrenthashmap,我正在读《实践中的Java》。第85页第5.2.1节讨论了ConcurrentHashMap及其优点。然而,书中有一部分声称 ConcurrentHashMap返回的迭代器弱一致。这 意味着该迭代器可以容忍并发修改, 遍历迭代器构造时存在的元素,以及 可能(但不保证)反映对集合的修改 在构造迭代器之后 从我的理解来看,并发程序中的整个同步点是允许线程以一致的方式访问共享资源,而ConcurrentHashMap并不能真正实现这一点。那为什么要用它呢 关键是在不需要同步时避免同步。如果您不介意在某

我正在读《实践中的Java》。第85页第5.2.1节讨论了ConcurrentHashMap及其优点。然而,书中有一部分声称

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

从我的理解来看,并发程序中的整个同步点是允许线程以一致的方式访问共享资源,而ConcurrentHashMap并不能真正实现这一点。那为什么要用它呢

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


因此,是的,当您需要同步和一致迭代器时,您需要一个替代方法—但如果您不需要,您可以利用
ConcurrentHashMap

ConcurrentHashMap
提供的更高效的迭代器。但是,它不应该跨线程保持一致


当您迭代一个
ConcurrentHashMap
时,迭代器会在您请求时获取一个哈希映射副本(并且该副本是以线程安全的方式创建的),然后您迭代该副本。是的,当您在该副本上迭代时,没有任何东西可以保证某些映射条目不会被删除。但是以这种方式删除的映射条目仍然存在于迭代器中。

一切取决于您需要的一致性有多强。如果您需要强一比互斥或其他操作子集将提供您所需要的

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

所以,如果您只需要跨线程共享map
ConcurrentHashMap
(比如在剧院里对预订它的人),它将提供您所需要的—如果您有许多工作线程,它可能会更快,因为您避免了互斥同步。另一方面,速度是要付出代价的——迭代器提供的视图在创建时不必对应于收集状态,并且可能会错过一些在后置词中创建的元素(通常在多处理器系统中,
发生在
之前,关系很复杂)


编辑:正如约翰·卫斯理亲王指出的那样,我在看和写的时候想到了
ConcurrentSkipListMap
<代码>ConcurrentHashMap。除了关于无锁的部分(以及来自它的所有内容,如保证吞吐量等)之外,大多数要点仍然有效.

ConcurrentHashMap在其实现中是否有同步功能?@Hossein:我不知道,但您可以尽可能轻松地查看源代码:)文档建议在写访问中可能有同步功能,但在读访问中没有:“但是,即使所有操作都是线程安全的,检索操作也不需要锁定,并且不支持以阻止所有访问的方式锁定整个表。“@Hossein:IIRC
ConcurrentHashMap
是无锁实现,因此它没有传统意义上的同步,而是使用原子和特殊算法来避免互斥。由于互斥体在某些应用程序中可能太重(将其自身的成本设置为asside,一次只允许运行一个线程),但它并没有完全同步,因此速度更快。@Maciej:
ConcurrentHashMap
是一种锁条带化实现,默认并发级别为16。@PrinceJohnWesley:Ups。抱歉-我的错误(我看到了
ConcurrentHashMap
read
ConcurrentSkipListMap
)。迭代器中可能不存在此类条目。否,“将”。如果它是“可能”而不是“可能”,那么您将得到一个
ConcurrentModificationException
。从Java SDK文档中可以看到“它们不会抛出ConcurrentModificationException”。。是的,因为在复制时,给定哈希桶的所有条目都会被复制,但在您进行迭代时,它们可能会从映射中删除。
ConcurrentHashMap
迭代器对副本无效。它可能会返回在
迭代器
创建之后添加的条目,甚至在您已经从迭代器接收到一些元素之后。我已经尝试过了,但在现实中有时会发生这种情况(Java8)。否则它就不会是弱一致的。