我已经深入研究并发性,并且很难理解并发数据结构中使用的一些设计,即并发哈希映射。
我做了一些陈述和粗体问题,请帮我确认并回答。
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;在第一次使用相同的密钥之后:
更新:感谢大家,这是其中的一天......
答案 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
表示未添加值,返回值是地图中已有的值。
明确检测结果!!