为什么没有将并发hashmap与操作结果放在一起?什么是putIfAbsent的用例?

时间:2017-03-15 19:18:01

标签: java multithreading concurrenthashmap

我已经深入研究并发性,并且很难理解并发数据结构中使用的一些设计,即并发哈希映射。

我做了一些陈述和粗体问题,请帮我确认并回答。

putIfAbsent无法告诉执行线程它是否实际用新值替换了键,或者它是否使用现有旧值,因为在这两种情况下它都将返回旧值。那么&#39; putIfAbsent&#39;是什么意思呢?与大多数用例一样,我们实际向最终客户/用户报告操作结果,我明白这可能是概括但仍然存在?我们大多数人可能会对Optional<Entry<K,V>> putIfAbsentAndReturnValueIfPut(K,V)感到高兴,这些都是:-)?

我从putIfAbsent原子性中获得了什么? 如果我想报告最终用户的操作结果,我仍然需要使用同步访问。

想象一下以下结构:

Map<String, Integer> map = new ConcurrentHashMap<>();

Outcome someMethod(String key, Integer value) {
   Integer returnedValue = map.putIfAbsent(key, value);// ??? so how do I know if I updated the value?
   map.get(key).equals(value); // even if I compare, I am not in  synchronized context

}

因此,如果我的密钥是UUID,那么从长远来看它可能会为新的地图条目生成重复的密钥,如何确保第二个线程调用&#34; put&#34;在第一次使用相同的密钥之后:

  • 甲。操作发生,一个线程试图放。
  • B中。运作结果 已知,所以第二个线程可以尝试重新生成一个新的UUID并尝试 再次发出或通知来电者操作失败了?

更新:感谢大家,这是其中的一天......

2 个答案:

答案 0 :(得分:5)

通过检查putIfAbsent的返回值,您始终可以了解该值是已添加还是已存在:

final ConcurrentMap<String,Object> map = new ConcurrentHashMap<>();
final Object old = map.putIfAbsent("hello", "world");

if (old != null) {

    // The value was already present and has not been modified
    // by the call.

} else {

    // There was no prior entry, and "world" has been assigned
    // as value for key "hello"
}

注意,如果地图实现接受null作为条目的值,则这仍然是不明确的。 (可能)因此,ConcurrentHashMap不接受null的键和值:

  

与Hashtable类似,但与HashMap不同,此类不允许将null用作键或值。

(如documentation中所述)

答案 1 :(得分:1)

putIfAbsent无法判断执行线程是否实际用新值替换了密钥,或者它是否使用现有旧密码,因为在这两种情况下它都将返回旧值。” < / p>

你真的读取 putIfAbsent()的javadoc吗?似乎您已阅读put()假设的javadoc putIfAbsent()行为相同。它没有:

  

如果指定的键尚未与值相关联(或映射为null),则将其与给定值相关联并返回null,否则返回当前值。

由于ConcurrentHashMap 允许null被用作键或值,因此您将确定该方法是否添加了该值。 null表示已添加值,非null表示未添加值,返回值是地图中已有的值。

明确检测结果!!