Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 同步对ConcurrentMap中给定密钥的访问_Java_Guava - Fatal编程技术网

Java 同步对ConcurrentMap中给定密钥的访问

Java 同步对ConcurrentMap中给定密钥的访问,java,guava,Java,Guava,我经常想访问(并可能添加/删除)给定ConcurrentMap的元素,以便一次只有一个线程可以访问任何单个键。最好的方法是什么?对密钥本身进行同步不起作用:其他线程可能通过equal实例访问同一密钥 如果答案只适用于由MapMaker构建的映射,那就足够了。您不能创建自己的类来扩展concurrentmap吗。 重写get(objectkey)方法,以便检查请求的key对象是否已被另一个线程“签出” 您还必须在concurrentmap中创建一个新方法,将项目“返回”到映射,以便其他线程可以再次

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


如果答案只适用于由
MapMaker

构建的映射,那就足够了。您不能创建自己的类来扩展concurrentmap吗。 重写
get(objectkey)
方法,以便检查请求的key对象是否已被另一个线程“签出”


您还必须在concurrentmap中创建一个新方法,将项目“返回”到映射,以便其他线程可以再次使用这些项目。

请参阅此处的简单解决方案

编辑:此解决方案具有从解锁到锁定的“先发生后清除”关系。然而,下一个解决方案(现已撤回)却没有。
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{}
private final V LOCK=…;//假价值
//如果钥匙映射到LOCK,则表示钥匙已锁定
ConcurrentMap=。。。;
V锁(钥匙)
V值;
while((value=map.putIfAbsent(key,LOCK))==LOCK)
//另一根线在我面前锁住了它
等待();
//现在,putIfAbsent()返回一个实值或null
//我只是成功地锁上了它
//我现在是这把钥匙的锁的主人
返回值;//供来电者处理
//只有密钥的锁所有者才能调用此方法
解锁(钥匙、值)
//我在钥匙上加了一把锁,让别人停下来
//现在我只需要用实际值来交换它
if(值!=null)
map.put(键、值);
else//map不接受空值
映射。删除(键)
notifyAll();
测试()
V值=锁(钥匙);
//创造价值
//解锁。
//我们有机会在这里为下一个工人指定一个新值
newValue=…;//如果要从映射中删除密钥,则为null
解锁(键,新值);//最后{}
这是相当混乱的,因为我们重用地图有两个不同的目的。最好将锁池作为一个单独的数据结构,将map简单地保留为k-v存储。

private static final Set lockedKeys=new HashSet();
    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);
        }
    }
私有无效锁(字符串键)引发InterruptedException{ 已同步(锁定键){ 而(!lockedKeys.add(key)){ lockedKeys.wait(); } } } 私有无效解锁(字符串密钥){ 已同步(锁定键){ 锁定钥匙。取下(钥匙); lockedKeys.notifyAll(); } } public void dosynchronouslyforeQualkeys(字符串键)抛出中断异常{ 试一试{ 锁(钥匙); //把你的代码放在这里。 //对于不同的键,它是并行执行的。 //对于相等的键,它是同步执行的。 }最后{ 解锁(钥匙); } }
  • 不仅可以是“字符串”,还可以是具有正确重写的“equals”和“hashCode”方法的任何类
  • 最后重试-非常重要-您必须保证在操作后解锁等待的线程,即使操作引发异常
  • 如果您的后端分布在多个服务器/JVM上,那么它将不起作用

事实上,我想知道为什么Maps没有返回key实例的方法
getKey(key)
。你是说你想在查找过程中(对我来说没有太大意义)或在从map获取值之后,在
ConcurrentMap
中同步访问吗?@JustYo如果你有一个相等的key实例,为什么您需要地图中的实例?如果该键是可变的,我会怀疑在这里使用该键的设计选择。@JustYo那么为什么要在该键上同步呢?我能想到两种情况:1。阻止对值的并发访问->对值进行同步。2.该值可能会被更改/替换,从而导致类似“脏读”的情况->添加一个间接级别(例如值持有者)并在该级别上进行同步。@如果要删除该值而不是替换该值,则Thomas选项2将不起作用。当然,也可以向值持有者添加一个“空”状态……我更喜欢sjr对链接问题的回答,而不是被接受的答案。为什么?当然,值必须是弱的,因此如果现在没有人需要锁,条目将从锁映射中逐出。映射中仍然有key->weakReference条目“垃圾收集器可能会回收映射中存在的密钥或值。如果发生这种情况,条目将自动从映射中消失。”如果我不再有对键的引用,我肯定不会有对值的引用(只能通过映射访问),相应的条目将被垃圾收集。我明白了。我对MapMaker不熟悉。但如果锁对象可以消失,然后重新创建,不同的线程可能会在不同的对象上同步,并且在关系可能不成立之前发生