Java 从ConcurrentMap.remove()获取密钥是否存在

Java 从ConcurrentMap.remove()获取密钥是否存在,java,concurrency,thread-safety,concurrenthashmap,Java,Concurrency,Thread Safety,Concurrenthashmap,在Java中,有,这返回以下之一: 预期值已存在,并且已被删除 预期值不存在,因此尚未删除 但我想得到的是: 预期值已存在,并且已被删除 该键下有一个值,但不是预期值,因此尚未删除该值 该键下没有值,因此尚未删除 如何以并发和线程安全的方式获取此信息 这就是我试图保护的代码 // attempt to remove the old session... if (!sessions.remove(player.getId(), existing)) { // it was not r

在Java中,有,这返回以下之一:

  • 预期值已存在,并且已被删除
  • 预期值不存在,因此尚未删除
但我想得到的是:

  • 预期值已存在,并且已被删除
  • 该键下有一个值,但不是预期值,因此尚未删除该值
  • 该键下没有值,因此尚未删除
  • 如何以并发和线程安全的方式获取此信息


    这就是我试图保护的代码

    // 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
    }
    

    我不明白你在医生身上看到的和你想要的。所以请让我写下来

    • A
      与值
      B
      关联
      remove(A,B)
      将返回trueremove-mapping A->B(这是您想要的)
    • A
      与值
      C
      关联
      remove(A,B)
      将返回
      false
      ,映射A->C将不会被删除(这是您想要的)
    • A
      与无值关联
      remove(A,null)
      将返回
      false
      (这是您想要的)

    换言之,似乎移除正是你想要的。。。或者,您的代码中可能存在另一个bug。

    您可以使用原子引用来提供帮助。假设您使用非空原子引用进行前置,您可以尝试在会话中使用引用的当前值为
    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
       }
    }
    
    AtomicReference=session.get(player.getId());
    if(参考比较数据集(现有,空){
    //1
    }否则{
    会话当前=ref.get();
    如果(当前!=null){
    //2
    }否则{
    //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.
        }
      }
    }
    
    class播放器{};
    ConcurrentMap players=新的ConcurrentHashMap();
    无效玩家id已更改(字符串id、玩家oldPlayer、玩家newPlayer){
    Player old=players.replace(id,newPlayer);
    if(old==oldPlayer){
    //预期值已存在,并已被替换。
    }否则{
    if(old==null){
    //该键下没有值,因此尚未删除。
    }否则{
    //该键下有一个值,但不是预期的值,因此它已被替换。
    //注意:这与你的要求略有不同。
    }
    }
    }
    
    不应该是
    sessions.remove(player.getId(),existing)
    而不是
    sessions.remove(sessions,existing)
    ?您能描述一下如何使用该映射的总体情况吗?您准确地描述了我的问题,后两种情况都不能从映射中删除条目(这是我想要的)它们还返回相同的结果,
    false
    ,这是不够的信息,因为我需要在后面的代码中区分这两种情况。