【问题标题】:Difference in semantics of computeIfAbsent between OpenJDK and Oracle JDKOpenJDK和Oracle JDK之间computeIfAbsent的语义差异
【发布时间】:2021-04-16 22:42:26
【问题描述】:

我注意到 Oracle 的 JDK 和 Open JDK 之间的 ConcurrentHashMap.computeIfAbsent 方法的语义存在严重差异。这很令人惊讶,所以我想记录一下,看看其他人是否注意到了这个问题,或者我是否误解了某些内容。

根据 Oracle JDK 的 Javadoc(从 v8 开始,一直到 v15),调用 mappingFunction 的语义是:

整个方法调用是原子执行的,因此每个键最多应用一次函数。

但是,当从两个不同的线程同时访问密钥时,我注意到该函数在我的程序中被调用了两次。深入挖掘,我注意到 Open JDK 的文档指定了不同的语义:

整个方法调用都是原子执行的。如果键不存在,则每次调用此方法时,提供的函数只调用一次,否则根本不调用。

这在行为上有很大的不同,并且与我在程序中观察到的一致。在我看来,Open JDK 的实现用处不大,因为正在构建的资源通常非常昂贵,并且应该最多创建一次。

【问题讨论】:

  • 对我来说“最多一次”与“仅一次或根本没有”似乎没有什么不同。也许您需要更具体地说明您的担忧?
  • OpenJdk 运行在 OracleJdk 之前,所以这个变化最终可能会成为 OracleJdk 的一部分。仅供参考,2019 年 11 月对 OpenJdk 进行了更改 - 这是提交,但抱歉我目前没有时间进一步调查:github.com/openjdk/jdk/commit/…
  • @John3136,再次阅读 javadoc sn-ps。 OpenJDK 指定该函数将被调用“如果键不存在,则每次调用此方法一次”,而 Oracle JDK 指定该函数“每个键最多调用一次”。大不同。
  • @racraman,非常有趣!感谢您分享。
  • 由于discussion,JavaDoc 被改写以试图更精确。

标签: java concurrency java.util.concurrent


【解决方案1】:

这在行为上有很大的不同

没有行为差异。它们的行为完全相同。

javadoc 的措辞被简单地改变了。

整个方法调用以原子方式执行,因此函数应用每个键最多一次

对比:

整个方法调用都是原子执行的。如果键不存在,则提供的函数调用一次每次调用此方法,否则根本不存在。

如果两个线程竞争同一个key,每个线程调用computeIfAbsent,所以可能会发生两次方法调用,每个线程调用一次,即每次调用@一次函数调用987654322@,如第二版所述。

原子保证意味着只有一个线程将值应用于映射,即函数的结果只应用于有问题的键一次,如第一个版本中所述。其他线程的函数调用结果直接丢弃。

如您所见,两个版本的 javadoc 描述都准确地描述了方法的行为。这些描述并不相互矛盾,因为它们描述了行为的两个不同方面

【讨论】:

  • 我认为可能的解释仍然存在细微差别。在 OP 的问题中,关注的是如果两个线程使用相同的键调用 putIfAbsent() 调用映射函数的次数。 “每个键一次” IMO 倾向于暗示映射函数只被调用一次。 “每次调用一次”留下了两​​个线程都调用映射函数并且一个结果被丢弃的可能性......
  • 我猜(希望)在这两种情况下都是一次,但我认为这两种措辞都不明确。需要对其进行更改以澄清这一点,或者明确地不指定它。
  • @JimGarrison 问题是“每个键一次”描述并没有声称只调用该功能一次,它声称只应用 功能一次。该函数可能会被调用(调用)无数次,但只有其中一个的结果会被分配(应用)给键。 “应用”并不意味着“调用”。另一个描述不太可能引起混淆/误解,所以我认为这是一个更好的描述,但它们都是完全准确的。
  • @JimGarrison,谢谢,我认为你很好地解释了这个问题。关于 Andreas 关于“调用”和“应用”之间区别的主张,我只会说函数的调用和应用是同义词,在一般情况下说。此外,如果 API 作者确实打算画出 Andreas 所建议的区别,那么该声明将简化为重言式,因为对于任何地图(除了多地图),一个关键点都只指向一个值。
  • @svcrunch 语句 a = foo() 是 2 个操作:1) 调用/调用/执行函数,2) 将结果分配/应用到 a。您不使用动词“应用”来描述函数调用。 --- 无论如何,关键是:行为/语义没有改变,只是措辞,这是问题中的主要误解。另一个误解是您希望该函数仅针对给定键调用一次,而实际上这两个描述都没有说明。
猜你喜欢
  • 2018-10-26
  • 2014-04-16
  • 2022-01-03
  • 2016-05-14
  • 1970-01-01
  • 2010-10-31
相关资源
最近更新 更多