这是一段来自 JavaDoc 关于 ConcurrentHashMap
的文章。它说检索操作通常不会阻塞,因此可能与更新操作重叠。这是否意味着 get()
方法不是线程安全的?
"However, even though all operations are thread-safe, retrieval operations do not entail locking, and there is not any support for locking the entire table in a way that prevents all access. This class is fully interoperable with Hashtable in programs that rely on its thread safety but not on its synchronization details.
Retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove). Retrievals reflect the results of the most recently completed update operations holding upon their onset."
最佳答案
get()
方法是线程安全的,其他用户为您提供了有关此特定问题的有用答案。
然而,虽然ConcurrentHashMap
是 HashMap
的线程安全插入替代品,重要的是要意识到,如果您正在执行多项操作,您可能必须显着更改您的代码。比如下面这段代码:
if (!map.containsKey(key))
return map.put(key, value);
else
return map.get(key);
在多线程环境中,这是一种竞争条件。您必须使用 ConcurrentHashMap.putIfAbsent(K key, V value)
并注意返回值,它告诉你 put 操作是否成功。阅读文档了解更多详情。
回答要求澄清为什么这是竞争条件的评论。
假设有两个线程 A
, B
这将在 map 中放置两个不同的值,v1
和 v2
分别具有相同的 key 。 key 最初不存在于 map 中。它们以这种方式交错:
- 话题
A
来电containsKey
并发现 key 不存在,而是立即挂起。 - 话题
B
来电containsKey
发现key不存在,有时间插入它的值v2
. - 话题
A
简历和插入v1
,“和平地”覆盖(因为put
是线程安全的)线程插入的值B
.
现在讨论 B
“认为”它已经成功插入了自己的值v2
,但 map 包含 v1
.这真是一场灾难,因为线程 B
可调用v2.updateSomething()
并且会“认为” map 的消费者(例如其他线程)可以访问该对象,并且会看到可能重要的更新(“例如:此访问者 IP 地址正在尝试执行 DOS,从现在开始拒绝所有请求”)。相反,该对象将很快被垃圾收集并丢失。
关于java - ConcurrentHashMap 完全安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14947723/