java - Oracle Java ConcurrentHashMap 的错误实现?

标签 java oracle java-8 concurrenthashmap

我正在测试 ConcurrentHashMap关于 Oracle 的 Java 8 实现:

ConcurrentMap<String, String> concurrentMap = new ConcurrentHashMap<>();
String result = concurrentMap.computeIfAbsent("A", k -> "B");
System.out.println(result);  // "B"
result = concurrentMap.putIfAbsent("AA", "BB");
System.out.println(result);  // null

Javadoc of computeIfAbsent是这么说的

Implementation Requirements:

The default implementation is equivalent to the following steps for this map, then returning the current value or null if now absent:

if (map.get(key) == null) {
    V newValue = mappingFunction.apply(key);
    if (newValue != null)
        return map.putIfAbsent(key, newValue);
}

它说然后返回当前值,如果现在不存在则返回 null。那么它不应该返回 null 吗?假设 putIfAbsent 也返回 null

我在这里错过了什么?

最佳答案

ConcurrentMap.computeIfAbsent 的代码示例没有反射(reflect)实际意图,很可能是 putIfAbsent 的非直觉行为导致的错误,而实现遵循记录的意图。这已在 JDK-8174087 中报告 和 fixed in Java 9

请注意 Map.computeIfAbsent 的契约(Contract)是

Implementation Requirements:

The default implementation is equivalent to the following steps for this map, then returning the current value or null if now absent:

if (map.get(key) == null) {
    V newValue = mappingFunction.apply(key);
    if (newValue != null)
        map.put(key, newValue);
}

省略 return 语句。但是明明说

Returns:

the current (existing or computed) value associated with the specified key, or null if the computed value is null

ConcurrentMap.computeIfAbsent的文档试图合并并发方面,落入 putIfAbsent 的非直观行为:

Implementation Requirements:

The default implementation is equivalent to the following steps for this map, then returning the current value or null if now absent:

if (map.get(key) == null) {
    V newValue = mappingFunction.apply(key);
    if (newValue != null)
        return map.putIfAbsent(key, newValue);
}

但它还是说

Returns:

the current (existing or computed) value associated with the specified key, or null if the computed value is null

并且记录的意图应该优先于代码示例。请注意,实际的 default implementation of ConcurrentMap.computeIfAbsent符合记录的意图:

@Override
default V computeIfAbsent(K key,
        Function<? super K, ? extends V> mappingFunction) {
    Objects.requireNonNull(mappingFunction);
    V v, newValue;
    return ((v = get(key)) == null &&
            (newValue = mappingFunction.apply(key)) != null &&
            (v = putIfAbsent(key, newValue)) == null) ? newValue : v;
}

所以 the implementation of ConcurrentHashMap.computeIfAbsent确实符合关于返回值的 ConcurrentMap.computeIfAbsentMap.computeIfAbsent 的文档意图,并且也等效于提供的 default 实现通过接口(interface)。

为了完整起见,Map.computeIfAbsent默认 实现是

default V computeIfAbsent(K key,
        Function<? super K, ? extends V> mappingFunction) {
    Objects.requireNonNull(mappingFunction);
    V v;
    if ((v = get(key)) == null) {
        V newValue;
        if ((newValue = mappingFunction.apply(key)) != null) {
            put(key, newValue);
            return newValue;
        }
    }

    return v;
}

关于java - Oracle Java ConcurrentHashMap 的错误实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46272108/

相关文章:

sql - 在 Oracle 的 to_char() 中显示时区描述

java - 如何使用 Java 8 计算当前时间和下周六之间的秒数

Java日期和时间从给定日期 "2019-12-03T10:00:00-06:00 "中删除时区,预期日期为 "2019-12-03T10:00:00"

java - HashMap 内二维数组的长度

java - 是否可以使用 JMX 在一个中央 MBean 服务器中注册或显示来自不同 VM 的 MBean?

JavaFX Accordion 效果

java - 如何从 Hibernate HQL (oracle) 可视化 SQL?

java - java中如何获取特定的日期类型

java - tools.jar 丢失 - 但仅在第一次调用时(Tomcat 8/Java 8/Axis)

java - 我按照 oracle 中关于 JLayer 的教程进行操作,但它不适用于此代码