【问题标题】:How to implement atomic getOrDefaultWithPut() based on getOrDefault() in ConcurrentHashMap?ConcurrentHashMap中如何基于getOrDefault()实现原子getOrDefaultWithPut()?
【发布时间】:2015-12-12 02:42:25
【问题描述】:

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

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

我的问题是:

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

"返回指定键映射到的值,或者先给定的默认值放入map中,如果这个map包含则返回默认值没有键映射。`"


我的解决方案:

目前我有一个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. synchronized 有必要吗?如果去掉会有什么坏处?
  3. 如果getOrDefaultWithPut(K key, V defaultValue)Wrapper 的唯一公共方法,那么此实现是否是线程安全的并且synchronized 是否必要?

【问题讨论】:

  • 通过使用同步,您似乎失去了并发哈希映射内部提供的所有并行性。此外,您应该在方法中使用 getOrDefault。只有当有人删除了语句 map.putIfAbsent 和 map.getOrDefault 之间的键时,您的代码才不起作用,在这种情况下,您将获得一个默认值,但键不会出现在 map 中(可以是理想情况下也是正确的,具体取决于您的用例)

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


【解决方案1】:

只需使用computeIfAbsent

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

退货

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

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

返回指定键映射到的值

这是现有值。

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

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


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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-21
      • 2011-11-06
      相关资源
      最近更新 更多