3

我们知道 ConcurrentHashMap 可以提供对多个线程的并发访问以提高性能,并且在这个类中,段是同步的(我说的对吗?)。问题是,这种设计能保证线程安全吗?假设我们有 30 多个线程访问和更改 ConcurrentHashMap 实例中由相同键映射的对象,我猜他们仍然需要为此排队,不是吗?

据我回忆,《Java Concurrency in Practice》一书说 ConcurrentHashMap 提供并发读取和相当水平的并发写入。在上述情况下,如果我的猜测是正确的,那么性能不会比使用 Collection 的静态同步包装器 API 更好吗?

感谢您的澄清,约翰

4

5 回答 5

6

您仍然必须同步对正在修改的对象的任何访问,并且您怀疑对同一密钥的所有访问仍将存在争用。性能提升来自对不同密钥的访问,这当然是更典型的情况。

于 2011-06-15T00:28:08.077 回答
2

问题是,这种设计能保证线程安全吗?

保证了map的线程安全;即,在多个线程同时执行更新的情况下,地图上的访问和更新具有定义明确且有序的行为。

它确实保证了键或值对象的线程安全。而且它不提供任何形式的更高级别的同步。

假设我们有 30 多个线程访问和更改由 ConcurrentHashMap 实例中的相同键映射的对象,我的猜测是,他们仍然需要为此排队,不是吗?

如果你有多个线程试图使用同一个键,那么它们的操作将不可避免地在某种程度上被序列化。这是不可避免的。

事实上,从简要查看源代码来看,ConcurrentHashMap如果对映射的特定段有太多争用,它看起来像是回退到使用传统锁。如果您有多个线程试图同时访问和更新同一个密钥,那将触发锁定。

于 2011-06-15T01:24:28.433 回答
2

所有ConcurrentMap可以给你的并发性是对映射本身的修改是原子完成的,并且任何写入都发生在任何读取之前(这很重要,因为它提供了来自映射的任何引用的安全发布。

安全发布意味着从映射中检索到的任何(可变)对象在放入映射之前都会被看到所有写入。但是,它对发布检索后所做的修改没有帮助。

但是,如果您有被多方修改的可变对象,则并发性和线程安全性通常很难推理和纠正。通常,您必须锁定才能使其正确。更好的方法通常是将不可变对象与ConcurrentMap条件 putIfAbsent/replace 方法结合使用,并以这种方式线性化您的算法。这种无锁风格往往更容易推理。

于 2011-06-15T00:42:26.937 回答
1

首先要记住,线程安全工具本身并不能保证线程安全地使用它

例如 putIfAbsent的if(!map.contains(k))map.put(k,v);构造不是线程安全的

并且每个值访问/修改仍然必须独立地进行线程安全

于 2011-06-15T00:29:59.003 回答
0

读取是并发的,即使对于相同的键也是如此,因此对于典型应用程序来说性能会更好。

于 2011-06-15T01:25:31.097 回答