2

JavaConcurrentMapには があり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

あなたがドキュメントで見たものとあなたが望むものとの間で私は理解していません。だから私に物事を書き留めさせてください。

  • キーAは値に関連付けられていますBremove(A, B)trueを返し、マッピングA-> B削除します(これはあなたが望むものです)。
  • キーAは値に関連付けられていますCremove(A, B)が返さfalseれ、マッピングA-> Cは削除されません(これはあなたが望むものです)。
  • キーAは値に関連付けられていません。remove(A, null)戻りfalseます(これはあなたが望むものです)。

言い換えれば、removeはあなたが望むことを正確に行うようです...あるいはあなたのコードに別のバグがあるかもしれません。

于 2012-01-04T10:46:23.153 に答える
0

AtomicReferenceを使用して支援することができます。null以外のAtomicReferenceを事前設定すると仮定すると、参照の現在の値がであるという述語を使用して、セッション内の値をnullにしようと試みることができます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 に答える
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 に答える