【问题标题】:List in ConcurrentHashMapConcurrentHashMap 中的列表
【发布时间】:2013-12-23 06:27:57
【问题描述】:
public static ConcurrentHashMap<Integer,Session> USER_SESSIONS...    

一切正常。但是如果允许系统被授权两个具有相同用户 ID 的会话呢?好吧,这大约是两台 PC 位于同一个帐户下,但会话不同。 尝试这样做:

ConcurrentHashMap<Integer,List<Session>> USER_SESSIONS....

...............

private void addUser(Session session){
   List<Session> userSessions = Server.USER_SESSIONS.get(session.mUserId);

   if(userSessions==null){
       userSessions = new List<Session>();
       userSessions.add(session);
       Server.USER_SESSIONS.put(session.getUserId(),userSessions);
   }else{
       userSessions.add(session);
   }
}

private void removeUser(Session session){
  List<Session> userSessions = Server.USER_SESSIONS.get(session.mUserId);

  if(userSessions!=null){
       userSessions.remove(session);
       if(userSessions.size()==0)
       {
           Server.USER_SESSIONS.remove(session.getUserId());
       }
  }
}

.................

private void workWithUsers(int userId){
    for(Session session : Server.USER_SESSIONS.get(userId))
    {
       <do it!>
    }
}

当然,所有这些方法都可以从不同的线程中调用,并且我得到了与 List 相关的错误。这是很自然的,因为当我有 foreach-list 会话时,removeUser 可以从另一个线程中删除。该怎么办?如何使这样的工作与所有线程列表一起工作 列表等待直到它占用线程完成它?还是这样做了:)

public static ConcurrentHashMap<Integer,ConcurrentHashMap<Session,Session>> USER_SESSIONS

因为 ConcurrentHashMap 线程安全。但我认为这是一个错误的决定。非常感谢您的帮助!

PS:JRE 1.6

请原谅我的英语。

【问题讨论】:

标签: java multithreading synchronization concurrenthashmap


【解决方案1】:

您可以尝试在您的情况下使用CopyOnWriteArrayListCopyOnWriteArraySet

【讨论】:

  • 大大增加RAM的消耗
【解决方案2】:

如果您不想使用 CopyOnWriteArrayList,可以使用 List myList = Collections.synchronizedList(new ArrayList&lt;String&gt;());

您唯一需要记住的是,在您将迭代列表的位置同步代码是强制。您可以在此处查看更多信息:Collections.synchronizedList and synchronized

【讨论】:

    【解决方案3】:

    使用List myList = Collections.synchronizedList(new ArrayList&lt;String&gt;());会更好
    但是如果读操作比写操作多,你也可以使用CopyOnWriteArrayList,它可以安全地迭代。

    【讨论】:

    【解决方案4】:

    在这种情况下,使用线程安全列表仍然不足以防止出现竞争条件。 同时两个 addUser 调用可能会覆盖彼此的 put。此外,在检查大小和 remoeUser 中的删除调用之间可能会发生添加。

    您需要这样的东西(未经测试)。此代码假定在调用它之前不会删除会话。

        private void addUser(Session session) {
        while (true) {
            List<Session> userSessions = Collections.synchronizedList(new ArrayList<Session>());
            List<Session> oldSessions = USER_SESSIONS.putIfAbsent(session.mUserId, userSessions);
            if (oldSessions != null) {
                userSessions = oldSessions;
            }
            userSessions.add(session);
    
            // want to make sure the map still contains this list and not another
            // so checking references
            // this could be false if the list was removed since the call to putIfAbsent
            if (userSessions == USER_SESSIONS.get(session.mUserId)) {
                break;
            }
        }
    }
    
    private void removeUser(Session session) {
        List<Session> userSessions = USER_SESSIONS.get(session.mUserId);
        if (userSessions != null) {
            // make whole operation synchronized to make sure a new session is not added
            // after the check for empty
            synchronized (userSessions) {
                userSessions.remove(session);
                if (userSessions.isEmpty()) {
                    USER_SESSIONS.remove(session.mUserId);
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-19
      • 2015-12-17
      • 2012-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多