我经常想要访问(并且可能添加/删除)给定 ConcurrentMap
的元素,以便一次只有一个线程可以访问任何单个键。做这个的最好方式是什么?同步 key 本身不起作用:其他线程可能通过 equal
实例访问相同的 key 。
如果答案仅适用于 guava 构建的 map 就足够了MapMaker
.
最佳答案
在这里查看一个简单的解决方案 Simple Java name based locks?
编辑:该解决方案从解锁到锁定具有明确的先行关系。然而,下一个解决方案(现已撤回)却没有。 ConcurrentMap
javadoc 太轻而无法保证这一点。
(Withdrawn) 如果你想重用你的 map 作为锁池,
private final V LOCK = ...; // a fake value
// if a key is mapped to LOCK, that means the key is locked
ConcurrentMap<K,V> map = ...;
V lock(key)
V value;
while( (value=map.putIfAbsent(key, LOCK))==LOCK )
// another thread locked it before me
wait();
// now putIfAbsent() returns a real value, or null
// and I just sucessfully put LOCK in it
// I am now the lock owner of this key
return value; // for caller to work on
// only the lock owner of the key should call this method
unlock(key, value)
// I put a LOCK on the key to stall others
// now I just need to swap it back with the real value
if(value!=null)
map.put(key, value);
else // map doesn't accept null value
map.remove(key)
notifyAll();
test()
V value = lock(key);
// work on value
// unlock.
// we have a chance to specify a new value here for the next worker
newValue = ...; // null if we want to remove the key from map
unlock(key, newValue); // in finally{}
这非常困惑,因为我们出于两个不同的目的重复使用 map 。最好将锁池作为一个单独的数据结构,让 map 简单地作为 k-v 存储。
关于java - 同步对 ConcurrentMap 中给定键的访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6758587/