4

如果在并发哈希映射上存在操作,您如何执行安全获取?(与 putIfAbsent 相同)

不好的例子,不是很安全的线程(检查然后采取行动):

ConcurrentMap<String, SomeObject> concMap = new ...

//... many putIfAbsent and remove operations

public boolean setOption(String id, Object option){
   SomeObject obj = concMap.get(id);

   if (obj != null){
      //what if this key has been removed from the map?
      obj.setOption(option);
      return true;
   }

   // in the meantime a putIfAbsent may have been called on the map and then this
   //setOption call is no longer correct

   return false;
}

另一个不好的例子是:

   public boolean setOption(String id, Object option){
       if (concMap.contains(id)){
           concMap.get(id).setOption(option);
           return true;
       }
       return false;
    }

这里的可取之处是不要通过同步添加、删除和获取操作来限制它们。

谢谢

4

4 回答 4

7

a 上的get()方法ConcurrentHashMap是原子的。由于该映射不允许空值,get()因此实现“如果存在则获取”:如果结果为null,则键不存在。

于 2010-12-04T14:03:26.397 回答
2

不要使用containsKey/ get,只需调用get. 如果该方法返回,null则该键不存在,否则该键存在,并且您获得了在get.

从文档:

返回指定键映射到的值,如果此映射不包含该键的映射,则返回 null。

这是您的第二个示例的外观:

public boolean setOption(String id, Object option) {

    SomeObject opt = concMap.get(id);
    if (opt == null)
        return false;

    opt.setOption(option);
    return true;
}
于 2010-12-04T14:00:53.250 回答
1

您似乎想要做的是在多个操作中锁定一个键。只有每个操作是原子的。这些都不是简单的锁定钥匙的方法,只能锁定地图。

但是,在“如果我删除一个键”的情况下,您所能做的就是将删除操作延迟到调用 setOption 之后。结果应该是一样的。

您似乎正在尝试解决可能不需要解决的问题。您还没有解释为什么在删除密钥后调用 setOption 或在等待删除密钥时调用是不好的。

于 2010-12-04T14:24:56.050 回答
0

如果您需要对 ConcurrentMap 中的单个键执行多个操作,您可以使用 Lock striping技术来减少争用,这是 Guava 框架的示例:

   private Striped<Lock> lock;
    public boolean setOption(String id, Object option) {
      try {
        Lock lock = concMap.get(id);
        lock.lock();
          if (concMap.contains(id)){
          concMap.get(id).setOption(option);
       return true;
   }
   return false;
        } finally {
         lock.unlock();
        }
    }

或者,由于 Java 8:ConcurrentMap.compute 是一种新的原子方法,请查看它是如何在键上完成的:

    concMap.compute(keyId, (key, value) -> {
    dosmth; ... return key;  });

ps 可能的变化是 ConcurrentMap.computeIfPresent() 等。

于 2016-04-13T18:39:01.830 回答