如何在ConcurrentHashMap中基于getOrDefault()实现原子getOrDefaultWithPut()?

How to implement atomic getOrDefaultWithPut() based on getOrDefault() in ConcurrentHashMap?

ConcurrentHashMap supports atomic getOrDefault(Object key, V defaultValue),其中

Returns the value to which the specified key is mapped, or the given default value if this map contains no mapping for the key.

我的问题是:

How can I enhance ConcurrentHashMap by providing an atomic operation, say getOrDefaultWithPut(Object key, V defaultValue), which

"Returns the value to which the specified key is mapped, or first put the the given default value into the map and then return the default value if this map contains no mapping for the key.`"


我的解决方案:

目前我有 Wrapper class 个

 private ConcurrentMap<K, V> map = new ConcurrentHashMap<>();

方法是:

public synchronized K getOrDefaultWithPut(K key, V defaultValue)
{
    map.putIfAbsent(key, defaultValue);
    return map.get(key);
}
  1. Is this implementation thread-safe?
  2. Is synchronized necessary? What bad would happen if it is removed?
  3. If getOrDefaultWithPut(K key, V defaultValue) is the only public method of Wrapper, is this implementation thread-safe and is synchronized necessary?

只需使用computeIfAbsent

If the specified key is not already associated with a value, attempts to compute its value using the given mapping function and enters it into this map unless null. The entire method invocation is performed atomically [...]

Returns

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

提供一个 mappingFunction 来生成您的默认值,这将满足您的要求。

Returns the value to which the specified key is mapped

这是现有值。

or first put the the given default value into the map and then return the default value if this map contains no mapping for the key

该方法将插入计算值(默认值),如果不是 null,并且 return 该计算值。


此解决方案不需要 synchronized。方法调用是原子的,因此是线程安全的。

差不多。您应该使用 putIfAbsent 返回的值,而不是执行另一个 .get,并且您不需要它 synchronized(无论如何,在这种情况下它毫无用处,除非所有其他调用者都知道也同步,这违背了 ConcurrentHashMap:

的目的
public V getOrDefaultWithPut(K key, V defaultValue) 
{
  V val = map.putIfAbsent(key, defaultValue);
  return val == null ? defaultValue : val;
}

Edit: computeIfAbsent 也可以,这只是简单了一点,因为在这种情况下你不需要定义一个函数,而且也是,我认为,作为一个答案,它的信息量更大,因为它实际上用你原来的方法解决了问题,而不是用不同的方法代替它。