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

时间:2015-12-12 02:42:26

标签: java collections synchronized java.util.concurrent concurrenthashmap

ConcurrentHashMap支持原子getOrDefault(Object key, V defaultValue),其中

  

返回指定键映射到的值,如果此映射不包含键的映射,则返回给定的默认值。

我的问题是:

  

如何通过提供原子操作来增强ConcurrentHashMap,比如getOrDefaultWithPut(Object key, V defaultValue)

     

"返回指定键映射到的值,或者首先 给定的默认值放入映射中,然后返回默认值此地图不包含密钥的映射。"

我的解决方案:

目前我有一个Wrapper

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

方法是:

public synchronized K getOrDefaultWithPut(K key, V defaultValue)
{
    map.putIfAbsent(key, defaultValue);
    return map.get(key);
}
  
      
  1. 这个实现是否是线程安全的?
  2.   
  3. synchronized是否必要?如果它被删除会发生什么不好?
  4.   
  5. 如果getOrDefaultWithPut(K key, V defaultValue)Wrapper的唯一公开方法,此实现是否是线程安全的并且synchronized是必需的?
  6.   

2 个答案:

答案 0 :(得分:5)

只需使用computeIfAbsent

即可
  

如果指定的键尚未与值关联,请尝试   使用给定的映射函数计算其值并输入它   进入此地图,除非null。执行整个方法调用   原子地[...]

     

<强>返回

     

与指定键关联的当前(现有或已计算)值,如果计算值为null,则为null

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

  

返回指定键映射到的值

这是现有价值。

  

或首先将给定的默认值放入地图中,如果此地图不包含该键的映射,则返回默认值

该方法将插入计算值(默认值),如果不是null,则返回该计算值。

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

答案 1 :(得分:3)

几乎。您应该使用由putIfAbsent返回的值而不是另一个.get,并且您不需要它synchronized(在这种情况下,它无论如何都相当无用,除非所有其他呼叫者都知道同步,否则它的目的是ConcurrentHashMap

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

编辑computeIfAbsent也有效,这只是一点点简单,因为在这种情况下你不需要定义一个函数,而且我认为,作为答案提供更多信息,因为它实际上用原始方法解决了问题,而不是用不同的方法替换它。