Java ConcurrentHashMap中的put()方法也是原子的吗?

Java ConcurrentHashMap中的put()方法也是原子的吗?,java,concurrency,Java,Concurrency,在ConcurrentHashMap中,putIfAbsent()是原子的。我的问题是ConcurrentHashMap中的方法put()也是原子的?文档中没有明确说明put或get是原子的。然而,缔约国指出: 检索反映了最近完成的更新操作在开始时的结果。(更正式地说,给定键的更新操作与报告更新值的该键的任何(非null)检索具有“发生在前”关系。) 这意味着如果一个线程使用相同的键执行put,另一个线程执行get,那么get将看到“在put之前”状态或“在put之后”状态。这实际上意味着,ge

ConcurrentHashMap
中,
putIfAbsent()
是原子的。我的问题是ConcurrentHashMap中的方法
put()
也是原子的?

文档中没有明确说明
put
get
是原子的。然而,缔约国指出:

检索反映了最近完成的更新操作在开始时的结果。(更正式地说,给定键的更新操作与报告更新值的该键的任何(非null)检索具有“发生在前”关系。)

这意味着如果一个线程使用相同的键执行
put
,另一个线程执行
get
,那么
get
将看到“在put之前”状态或“在put之后”状态。这实际上意味着,
get
put
相互之间是原子的,对于其他明确的原子操作。。。所有这些都适用于给定的密钥。事实上,如果不是这样的话,
ConcurrentHashMap
就不是常规/直观意义上的线程安全

然而,javadocs并没有为涉及不同密钥的操作提供强有力的保证。因此原子性是有限的

这种原子性不是一个特别有趣或有用的性质。例如,虽然
put
get
分别是原子的,但是
put
后跟
get
不是原子的。很难看出您将如何利用这些操作的有限原子性。。。除了一般的线程安全之外

(依我看,这可能是他们不愿意在javadoc中明确提到
get
put
原子性的原因。)


更有趣的特性是更复杂操作的原子性(或非原子性)。例如,像
putIfAbsent
compute
merge
这样的操作是原子操作,但批量操作不是原子操作。

文档中没有明确说明
put
get
是原子操作。然而,缔约国指出:

检索反映了最近完成的更新操作在开始时的结果。(更正式地说,给定键的更新操作与报告更新值的该键的任何(非null)检索具有“发生在前”关系。)

这意味着如果一个线程使用相同的键执行
put
,另一个线程执行
get
,那么
get
将看到“在put之前”状态或“在put之后”状态。这实际上意味着,
get
put
相互之间是原子的,对于其他明确的原子操作。。。所有这些都适用于给定的密钥。事实上,如果不是这样的话,
ConcurrentHashMap
就不是常规/直观意义上的线程安全

然而,javadocs并没有为涉及不同密钥的操作提供强有力的保证。因此原子性是有限的

这种原子性不是一个特别有趣或有用的性质。例如,虽然
put
get
分别是原子的,但是
put
后跟
get
不是原子的。很难看出您将如何利用这些操作的有限原子性。。。除了一般的线程安全之外

(依我看,这可能是他们不愿意在javadoc中明确提到
get
put
原子性的原因。)


更有趣的特性是更复杂操作的原子性(或非原子性)。例如,
putIfAbsent
compute
merge
等操作是原子操作,但批量操作不是原子操作。

如果我负责此API,我会将其添加到文档中,但有一个解释:

put
本质上是一个单数操作。与中一样,put的定义(来自
java.util.Map
的定义)是原子的

当然,仅仅因为某些方法任务是以原子方式描述的,并不意味着实现是原子的,而对于集合框架中的许多东西来说,它们不是原子的。ArrayList的add方法是原子描述,但不是原子实现

区别在于,添加作业的描述只是“将元素添加到末尾”。它不是“搜索结束节点,一旦找到,将此元素添加为它的尾部引用”。它不是“获取列表的大小并记住它”。然后,检查此列表的容量,如果它不足以向其中添加项目,请先按增长因子扩展容量,然后将先前获得的“大小”索引的值设置为传入的对象

尽管后一个冗长的描述或多或少正确地描述了ArrayList.add的实际功能

因此,
ConcurrentHashMap
的javadoc在类级别和方法级别协同工作:

put()
本质上被描述为一个原子操作,而
putIfAbsent
描述根本不是原子操作。它被明确描述为一个两步过程;甚至在名字里放置,如果不存在-这是一个两步名称。因此,DOCS需要走出去说:即使听起来像两步操作,也可以认为它是原子的。

然后CHM的javadoc类说所有的原子操作实际上都是原子实现的

为了进行对比,类似于
putAll
的内容被描述为一个多步骤过程,CHM文档没有明确说明
putAll
是原子的。事实并非如此。您可以观察到您正在使用
putAll
添加的内容中有一半已添加到单独的列表中(putAll的行为与<