【问题标题】:Get whether key existed from ConcurrentMap.remove()从 ConcurrentMap.remove() 获取 key 是否存在
【发布时间】:2012-01-04 10:26:31
【问题描述】:

在 Java 的 ConcurrentMap 中,有 remove(key, expectedValue),它返回以下之一:

  • 预期值存在但已被删除。
  • 预期值不存在,因此尚未删除。

但我想得到的是以下之一:

  1. 预期值存在但已被删除。
  2. 该键下有一个值,但不是预期的值,因此尚未删除。
  3. 该键下没有值,因此尚未删除。

如何以并发和线程安全的方式获取这些信息?


这是我要验证的代码

// attempt to remove the old session...
if (!sessions.remove(player.getId(), existing)) {
    // it was not removed...
    if (sessions.containsKey(player.getId())) { // TODO threadsafe
        // ...because in the meantime some other thread logged in as that user
        throw new ServiceError(LobbyService.ERR_LOGIN_INVALID, Maps.create("reason", "already-logged-in"));
    } else {
        // ...because it was no longer there, which is as it should be
    }
} else {
    // it was removed, which is bad, because it shouldn't have been there still
    log.warn("Kicking old session of " + player.getId() + " failed");
}

或概括:

if (!sessions.remove(key, expected)) {
    if (sessions.containsKey(key)) {    // TODO threadsafe
        // 2
    } else {
        // 3
    }
} else {
    // 1
}

【问题讨论】:

  • 不应该是sessions.remove(player.getId(), existing) 而不是sessions.remove(sessions, existing) 吗?
  • 您能描述一下您如何使用该地图的总体情况吗?

标签: java concurrency thread-safety concurrenthashmap


【解决方案1】:

我不明白您在文档中看到的内容与您想要的内容之间的关系。所以请让我把事情写下来。

  • 键A与值B相关联。 remove(A, B) 将返回 true 并删除映射 A->B(这是您想要的)。
  • 键A与值C相关联。 remove(A, B) 将返回 false,映射 A->C 不会被删除(这是你想要的)。
  • key A 没有关联任何值。 remove(A, null) 将返回 false(这是你想要的)。

换句话说,似乎 remove 正是你想要的......或者你的代码中可能存在另一个错误。

【讨论】:

  • 您准确地描述了我的问题,后两种情况都不会从地图中删除条目(这是我想要的)并且它们也返回相同的结果,false,这还不够信息,因为我需要在后面的代码中区分这两种情况。
【解决方案2】:

您可以使用 AtomicReference 来提供帮助。假设您使用非空 AtomicReference 进行预填充,您可以尝试使用引用的当前值为 existing 的谓词将会话中的值设为空。如果是,则您从地图中“删除”,否则 AtomicReference 的当前值就是当前存在的值

AtomicReference<Session> ref = session.get(player.getId());
if (ref.compareAndSet(existing,null) {
   //1
}else{
   Session current = ref.get();
   if(current != null){
       //2
   }else{
      //3
   }
}

【讨论】:

    【解决方案3】:

    此代码似乎几乎提供您所要求的,但我不确定它是否能满足您的要求。

    能否请您详细说明您真正想做的事情?

    class Player {};
    ConcurrentMap<String,Player> players = new ConcurrentHashMap();
    
    void playerIDChanged(String id, Player oldPlayer, Player newPlayer) {
      Player old = players.replace(id, newPlayer);
      if ( old == oldPlayer ) {
        // The expected value was there and has been REPLACED.
      } else {
        if ( old == null ) {
          // There is no value under that key, so it has not been removed.
        } else {
          // There is a value under that key, but not the expected one, so it HAS been replaced.
          // NB: This is slightly different from what you are asking for.
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-01-27
      • 2021-04-29
      • 1970-01-01
      • 1970-01-01
      • 2021-04-12
      • 2018-05-30
      • 1970-01-01
      • 2012-10-01
      • 2017-09-12
      相关资源
      最近更新 更多