同步对 ConcurrentMap 中给定键的访问

Ale*_*nov 5 java guava

我经常想要访问(并且可能添加/删除)给定的元素ConcurrentMap,以便一次只有一个线程可以访问任何单个键。做这个的最好方式是什么?同步密钥本身不起作用:其他线程可能通过equal实例访问同一密钥。

如果答案仅适用于guava MapMaker构建的地图就足够了。

irr*_*ble 3

在这里查看一个简单的解决方案基于简单 Java 名称的锁?

编辑:该解决方案具有从解锁到锁定的明确发生之前关系。然而,现在已撤回的下一个解决方案却没有。javadocConcurrentMap太轻,无法保证这一点。


(已撤回) 如果你想将你的地图重新用作锁池,

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{}
Run Code Online (Sandbox Code Playgroud)

这非常混乱,因为我们为了两个不同的目的而重复使用地图。最好将锁池作为一个单独的数据结构,而将map简单地作为kv存储。