2

在 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
}
4

3 回答 3

1

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

  • keyA与 value 相关联Bremove(A, B)将返回 true删除映射 A->B (这是你想要的)。
  • keyA与 value 相关联Cremove(A, B)将返回false,映射 A->C 不会被删除(这是你想要的)。
  • A与没有值相关联。remove(A, null)将返回false(这是你想要的)。

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

于 2012-01-04T10:46:23.153 回答
0

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

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

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.
    }
  }
}
于 2012-01-11T20:43:19.100 回答
0

您可以使用 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
   }
}
于 2012-01-04T17:37:43.680 回答