在Java的ConcurrentMap
中,有remove(key, expectedValue)
,这会返回以下内容之一:
但我想得到的是:
如何以并发且线程安全的方式获取此信息?
这是我正在尝试安全的代码
// 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
}
答案 0 :(得分:1)
我不明白你在文档中看到的内容和你想要的内容。所以请让我写下来。
A
与值B
相关联。 remove(A, B)
将返回true 和删除映射A-> B(这是您想要的)。A
与值C
相关联。 remove(A, B)
将返回false
,mappping A-> C不会被删除(这就是你想要的)。A
与没有值相关联。 remove(A, null)
将返回false
(这是您想要的)。换句话说,似乎删除了你想要的东西......或者你的代码中可能还有另一个错误。
答案 1 :(得分:0)
您可以使用AtomicReference来提供帮助。假设您使用非null 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
}
}
答案 2 :(得分: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.
}
}
}