繁体   English   中英

在ConcurrentHashMap中列出

[英]List in ConcurrentHashMap

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

抱歉我的英语。

您可以使用List myList = Collections.synchronizedList(new ArrayList<String>()); 如果您不想使用CopyOnWriteArrayList。

您唯一需要记住的是, 必须同步代码,您将在列表上进行迭代。 您可以在此处查看更多信息: Collections.synchronizedList和synchronized

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

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

    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);
            }
        }
    }
}

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

使用List myList = Collections.synchronizedList(new ArrayList<String>()); 会更好
但是如果有比read更多的读操作,你也可以使用可以安全迭代的CopyOnWriteArrayList

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM