简体   繁体   English

OpenJDK和Oracle JDK之间computeIfAbsent的语义差异

[英]Difference in semantics of computeIfAbsent between OpenJDK and Oracle JDK

I've noticed a serious difference in the semantics of the ConcurrentHashMap.computeIfAbsent method between Oracle's JDK and Open JDK.我注意到 Oracle 的 JDK 和 Open JDK 之间的ConcurrentHashMap.computeIfAbsent方法的语义存在严重差异。 This is surprising, so I wanted to make note of it, and see whether others have noticed this issue, or if I'm misinterpreting something.这很令人惊讶,所以我想记下它,看看其他人是否注意到了这个问题,或者我是否误解了某些东西。

According to the Javadoc for Oracle's JDK (beginning with v8, and continuing to v15) the semantics for invocation of the mappingFunction are:根据 Oracle JDK 的 Javadoc(从 v8 开始,一直到 v15),调用 mappingFunction 的语义是:

The entire method invocation is performed atomically, so the function is applied at most once per key.整个方法调用以原子方式执行,因此每个键最多应用一次 function。

However, I noticed the function being invoked twice in my program when the key was accessed simultaneously from two different threads.但是,当从两个不同的线程同时访问密钥时,我注意到 function 在我的程序中被调用了两次。 Digging deeper, I noticed that Open JDK's documentation specifies different semantics:深入挖掘,我注意到 Open JDK 的文档指定了不同的语义:

The entire method invocation is performed atomically.整个方法调用以原子方式执行。 The supplied function is invoked exactly once per invocation of this method if the key is absent, else not at all.如果密钥不存在,则每次调用此方法时,提供的 function 仅调用一次,否则根本不调用。

That's quite a big difference in behavior, and consistent with what I observed in my program.这在行为上有很大的不同,并且与我在程序中观察到的一致。 Open JDK's implementation is far less useful, in my opinion, because the resource being constructed is oftentimes very expensive and it should be created at most once.在我看来,Open JDK 的实现用处不大,因为正在构建的资源通常非常昂贵,并且最多只能创建一次。

That's quite a big difference in behavior这是行为上的很大差异

There is no behavior difference.没有行为差异。 They behave exactly the same.它们的行为完全相同。

The wording of the javadoc has simply been changed. javadoc 的措辞已经简单地改变了。

The entire method invocation is performed atomically, so the function is applied at most once per key .整个方法调用是原子执行的,因此每个 key最多应用一次function 。

vs:与:

The entire method invocation is performed atomically.整个方法调用以原子方式执行。 The supplied function is invoked exactly once per invocation of this method if the key is absent, else not at all.如果密钥不存在,则每次调用此方法时,提供的 function 仅调用一次,否则根本不调用。

If two threads are in a race condition for the same key, each thread calls computeIfAbsent , so two invocations of the method may occur, one invocation per thread, ie one invocation of the function per call of computeIfAbsent , as described in the second version.如果两个线程对同一个键处于竞争状态,则每个线程都会调用computeIfAbsent ,因此可能会发生两次方法调用,每个线程调用一次,即每次调用 computeIfAbsent 都会调用computeIfAbsent ,如第二个版本中所述。

The atomic guarantee means that only one thread applies the value to the map, ie the result of the function is only applied once for the key in question, as described in the first version.原子保证意味着只有一个线程将值应用于map,即 function 的结果仅应用于相关密钥一次,如第一个版本中所述。 The result of the function call made by the other thread is simply discarded.其他线程进行的 function 调用的结果被简单地丢弃。

As you can see, both versions of the javadoc description accurately describes the behavior of the method.如您所见,两个版本的 javadoc 描述都准确地描述了方法的行为。 The descriptions don't contradict each other, as they describe two different aspects of the behavior.这些描述并不相互矛盾,因为它们描述了行为的两个不同方面

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM