如何锁定 ConcurrentHashMap 中的键

问题描述 投票:0回答:2

我正在将一个由线程创建的对象缓存到地图中。创建对象的成本很高,因此我不希望运行多个线程来创建对象,因为 put() 尚未返回。一旦线程尝试为该键创建对象,其他线程就不应该尝试创建该对象,即使 put 尚未完成。使用computeIfAbsent()是否可以获取该特定密钥的“锁”?如果没有,还有其他方法可以实现吗?

java concurrenthashmap
2个回答
12
投票

> 使用computeIfAbsent() 可以获取该特定密钥的“锁”吗?

是的;根据

ConcurrentHashMap.computeIfAbsent(...)
的 Javadoc:

整个方法调用都是原子执行的,因此每个键最多应用该函数一次。

这确实是该方法的全部要点。

但是,要明确的是,锁并不完全特定于那一把钥匙;相反,

ConcurrentHashMap
通常通过将映射分成多个段,并为每个段拥有一个锁来工作。这允许大量并发,并且通常是最有效的方法;但您应该意识到,这意味着某些线程可能会阻塞您的对象创建,即使它们实际上没有触摸同一个键。

如果这对您来说是个问题,那么另一种方法是使用类似

ConcurrentHashMap<K, AtomicReference<V>>
的方法来将 adding 映射条目与 populate 映射条目解耦。 (
AtomicReference<V>
没有
computeIfAbsent
方法,但此时您可以使用普通的双重检查锁定以及
get()
synchronized
的组合。)


0
投票

我最近有一个类似的需求,尽管在我的情况下,如果多个并发线程创建要放入映射中的对象就可以了,只要只有一个线程最终实际放入其对象即可。为此,我最终使用了这种方法:

如果缺席则放置

public V putIfAbsent(K key, V value);

如果指定的键尚未与值关联,则将其与给定的值关联。这相当于:

if (!map.containsKey(key))
   return map.put(key, value);
else
   return map.get(key);

除了该操作是原子执行的。

© www.soinside.com 2019 - 2024. All rights reserved.