简体   繁体   English

如何锁定 ConcurrentHashMap 中的键

[英]How to lock on key in a ConcurrentHashMap

I am caching an object, which is created by a thread, into a map.我正在将一个由线程创建的对象缓存到地图中。 The creation of the object is expensive, so I don't want multiple threads running to create the object because the put() hasn't returned.对象的创建是昂贵的,所以我不希望多个线程运行来创建对象,因为 put() 没有返回。 Once a thread tries to create an object for that key, other threads shouldn't try to create the object, even if put is not yet complete.一旦一个线程尝试为该键创建对象,其他线程不应尝试创建该对象,即使 put 尚未完成。 Will using computeIfAbsent() work to acquire a 'lock' on that particular key?使用 computeIfAbsent() 是否可以在该特定键上获得“锁定”? If not, is there another way to achieve this?如果没有,还有其他方法可以实现这一目标吗?

> Will using computeIfAbsent() work to acquire a 'lock' on that particular key? > 使用 computeIfAbsent() 是否可以在该特定键上获得“锁定”?

Yes;是的; per the Javadoc for ConcurrentHashMap.computeIfAbsent(...) :根据ConcurrentHashMap.computeIfAbsent(...)的Javadoc

The entire method invocation is performed atomically, so the function is applied at most once per key.整个方法调用以原子方式执行,因此每个键最多应用一次该函数。

That's really the whole point of the method.这就是方法的全部意义所在。

However, to be clear, the lock is not completely specific to that one key;但是,需要明确的是,锁并不完全特定于那把钥匙。 rather, ConcurrentHashMap typically works by splitting the map into multiple segments, and having one lock per segment.相反, ConcurrentHashMap通常通过将映射拆分为多个段,并且每个段拥有一个锁来工作。 This allows a great deal of concurrency, and is usually the most efficient approach;这允许大量并发,通常是最有效的方法; but you should be aware that it means that some threads might block on your object creation even if they're not actually touching the same key.但是您应该知道,这意味着某些线程可能会阻塞您的对象创建,即使它们实际上并未触及同一个键。

If this is a problem for you, then another approach is to use something like ConcurrentHashMap<K, AtomicReference<V>> to decouple adding the map entry from populating the map entry.如果这对您来说是个问题,那么另一种方法是使用诸如ConcurrentHashMap<K, AtomicReference<V>>之类的东西来将添加映射条目与填充映射条目分离。 ( AtomicReference<V> doesn't have a computeIfAbsent method, but at that point you can just use normal double-checked locking with a combination of get() and synchronized .) AtomicReference<V>没有computeIfAbsent方法,但此时您可以使用普通的双重检查锁定与get()synchronized的组合。)

Took some research, but we were probably after is the Java ConcurrentHashMap equivalent of .NET's .TryAdd method.进行了一些研究,但我们可能追求的是 Java ConcurrentHashMap等效于 .NET 的.TryAdd方法。 Which is Java world is:哪个是Java世界是:

putIfAbsent 放置如果不存在

public V putIfAbsent(K key, V value);

If the specified key is not already associated with a value, associate it with the given value.如果指定的键尚未与值关联,则将其与给定值关联。 This is equivalent to:这相当于:

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

except that the action is performed atomically.除了动作是原子执行的。

I knew an atomic add operation had to exist;我知道必须存在原子add操作; just was not easy to find.只是不容易找到。 (which is odd because it's like the very first thing anyone would ever need to call). (这很奇怪,因为这就像任何人都需要打电话的第一件事)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM