OpenJDK和Oracle JDK在computeInfoAbsent语义上的差异



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

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

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

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

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

这是一个相当大的行为差异,与我在程序中观察到的一致。在我看来,开放JDK的实现用处要小得多,因为构建的资源通常非常昂贵,并且最多应该创建一次

的行为有很大的不同

没有行为差异。他们的行为完全一样。

javadoc的措辞已经简单地改变了。

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

vs:

整个方法调用都是原子执行的。提供的函数被调用,每次调用该方法仅一次如果键不存在,则完全不调用。

如果两个线程对同一个键处于竞争状态,则每个线程都会调用computeIfAbsent,因此可能会发生两次方法调用,每个线程一次调用,即每次调用computeIfAbsent一次函数调用,如第二个版本中所述。

原子保证意味着只有一个线程将值应用于映射,即函数的结果只应用于有问题的键一次,如第一个版本中所述。由另一个线程进行的函数调用的结果被简单地丢弃。

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

最新更新