在ConcurrentMap中同步对给定键的访问

问题描述 投票:3回答:3

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

如果答案仅适用于guava MapMaker制作的地图,那就足够了。

java guava
3个回答
2
投票

在这里查看一个简单的解决方案Simple Java name based locks?

编辑:这个解决方案有一个明确的发生 - 从解锁到锁定的关系。然而,现在撤回的下一个解决方案却没有。 ConcurrentMap javadoc太轻了,无法保证。


(已撤消)如果要将地图重新​​用作锁定池,

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简单地保留为k-v存储。


0
投票

你不能只创建自己的扩展concurrentmap的类。覆盖get(Object key)方法,以便检查所请求的密钥对象是否已被另一个线程“检出”?

您还必须在您的concurrentmap中创建一个新方法,将项目“返回”到地图,以便它们再次可用于另一个线程。


0
投票
    private static final Set<String> lockedKeys = new HashSet<>();

    private void lock(String key) throws InterruptedException {
        synchronized (lockedKeys) {
            while (!lockedKeys.add(key)) {
                lockedKeys.wait();
            }
        }
    }

    private void unlock(String key) {
        synchronized (lockedKeys) {
            lockedKeys.remove(key);
            lockedKeys.notifyAll();
        }
    }

    public void doSynchronouslyOnlyForEqualKeys(String key) throws InterruptedException {
        try {
            lock(key);

            //Put your code here.
            //For different keys it is executed in parallel.
            //For equal keys it is executed synchronously.

        } finally {
            unlock(key);
        }
    }
  • key不仅可以是'String',还可以是任何具有正确覆盖'equals'和'hashCode'方法的类。
  • try-finally - 非常重要 - 即使您的操作引发异常,您也必须保证在操作后解锁等待的线程。
  • 如果您的后端分布在多个服务器/ JVM上,它将无法工作。
© www.soinside.com 2019 - 2024. All rights reserved.