簡體   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