【问题标题】:How to add, and remove HashMap values by insertion order?如何按插入顺序添加和删除 HashMap 值?
【发布时间】:2017-01-08 15:35:24
【问题描述】:

我想知道如何根据他们的唯一 ID 和 ID 会话映射连接的用户,以便当该 ID 的会话超过 3 个时,首先连接的用户会从哈希图中删除,依此类推.

例子:

UserID:3 Session:1980002
UserID:3 Session:2841111
UserID:3 Session:84848

UserID 已经包含 3 个活动会话,最旧的会话被删除并调用 KillSession,让位于新会话。

UserID:3 Session:2841111
UserID:3 Session:84848
UserID:3 Session:4848880

代码:

public void onHTTPCupertinoStreamingSessionCreate(HTTPStreamerSessionCupertino httpSession) {
    String User_Session = httpSession.getSessionId();
    String Client_ID = httpSession.getProperties().getPropertyStr("sql_client_id");
    /* Verifies that there are already 3 active sessions and removes the oldest, 
    since the limit of simultaneous sessions is 3 for each user,
    and add to hashmap, Client_ID and User_Session */
}

public void onHTTPCupertinoStreamingSessionDestroy(IHTTPStreamerSession httpSession) {
    String User_Session = httpSession.getSessionId();
    //remove from hashmap, Client_ID based on session User_Session
}

public void KillSession(int SessionId){ 
    IApplicationInstance Instance = applicationInstance;
    IHTTPStreamerSession sessions = Instance.getHTTPStreamerSessions().get(SessionId);
    sessions.rejectSession();
    //remove from hashmap, Client_ID based on session User_Session
}

Client_ID是用户在数据库中的id,User_Session是wowza中为每个连接生成的唯一会话,这个会话不具有相等的值,即如果同一个Client_ID连接了多次,那每个会话的值都会有所不同。

也就是说,基本上我的难点就是挂载hashmap,我该怎么做呢?

【问题讨论】:

  • 我不明白。用户 ID 是您地图的键(HashMap 还是其他类型)?如果是这样,我建议将ArrayDeque<Session> 作为地图的值。如果ArrayDeque 的大小已经为 3,则取出第一个会话并将其终止,然后在末尾添加新会话。您可以将Queue<Session> 用于映射值类型,但ArrayDeque<Session> 用于实际实例。
  • HashMap<String, String>HashMap<Integer, Integer> 无法从一个用户 ID 映射到三个会话 ID。它只能保存每个键一次,并且该键只有一个值。

标签: java hashmap limit wowza linkedhashmap


【解决方案1】:

如果要按插入顺序添加和删除,请使用 LinkedHashMap。 (可能有帮助的简单版本)

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapExample {
    static class User {
        LinkedHashMap<String, Integer> sessionIds = new LinkedHashMap<>();
        int userId;

        public User(int userId) {
            this.userId = userId;
        }

        public void addSession(String someField, int sessionId) {
            this.sessionIds = new LinkedHashMap<String, Integer>(sessionIds) {
                protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
                    return size() > 3;
                }
            };
            sessionIds.put(someField, sessionId);
        }

        @Override
        public String toString() {
            return "User{" +
                    "sessionIds=" + sessionIds +
                    ", userId=" + userId +
                    '}';
        }
    }

    public static void main(String[] args) {
        User user1 = new User(1);
        user1.addSession("1980002", 1980002);
        user1.addSession("84848", 84848);
        user1.addSession("2841111", 2841111);
        System.out.println(user1);
        user1.addSession("999999", 999999);
        System.out.println(user1);
        user1.addSession("777777", 777777);
        System.out.println(user1);
    }
}

【讨论】:

  • 我对 HashMap 了解不多,你能给我举个例子来说明我如何做到这一点吗?这是我的难点,使用 hashmap 并计算同一个 UserID 有多少会话处于活动状态,如果超过 3 个,请按照我放置的示例进行操作。
  • 嗨,佛罗里达,您能提供地图的键值结构吗?
  • 我没有准备好映射,但值 K、V 可以在 Stringint 中。
  • 嗨,我已经用一个简单的例子来更新我的答案,说明如何使用 LinkedHashMap。
  • 感谢您的演示。您正在为每个新的会话 ID 创建一个新的 LinkedHashMap 实例,这是一种浪费。而且您并没有将它用于从一种事物到另一种事物的映射,而是作为一个集合,看起来(这里不需要,因为同一用户不会出现重复的会话 ID)。 removeEldestEntry() 的覆盖是优雅的。您可能需要添加 @Override 注释。
【解决方案2】:

如果我的理解正确,您希望每个用户/客户端 ID 最多存储三个会话 ID,我真的不认为 LinkedHashMap 会帮助您。 LinkedHashMap 维护插入顺序是正确的,而不是 HashMap

我有一个不同的建议给你。为了让事情分开,我建议用这个小辅助类来保存地图:

public class MapOfSessions {

    private Map<String, Queue<Integer>> sessionMap = new HashMap<>();

    public int countSessions(String clientId) {
        Queue<Integer> q = sessionMap.get(clientId);
        if (q == null) {
            return 0;
        } else {
            return q.size();
        }
    }

    public int removeOldestSession(String clientId) {
        return sessionMap.get(clientId).remove();
    }

    public void add(String clientId, int sessionId) {
        Queue<Integer> q = sessionMap.get(clientId);
        if (q == null) {
            q = new ArrayDeque<>();
            sessionMap.put(clientId, q);
        }
        q.add(sessionId);
    }

    public void remove(String clientId, int sessionId) {
        sessionMap.get(clientId).remove(sessionId);
        // if queue is now empty, may remove key from map
    }
}

现在映射是保持客户端 ID 和会话 ID 之间的对应关系,而 Queue 保持插入顺序。

有了这个,您可以通过以下方式解决您的任务。我已将 killSession() 从地图中删除,并将该责任交给了调用者 onHTTPCupertinoStreamingSessionCreate()

private int maxSessionsPerUser = 3;
private MapOfSessions sessionsPerUser = new MapOfSessions();

public void onHTTPCupertinoStreamingSessionCreate(HTTPStreamerSessionCupertino httpSession) {
    // use camel case for variable names: begin with lowercase, no underscores
    String userSession = httpSession.getSessionId();
    String clientId = httpSession.getProperties().getPropertyStr("sql_client_id");
    /* Verifies that there are already 3 active sessions and removes the oldest, 
    since the limit of simultaneous sessions is 3 for each user,
    and add to hashmap, clientId and userSession */
    if (sessionsPerUser.countSessions(clientId) == maxSessionsPerUser) {
        int oldestSession = sessionsPerUser.removeOldestSession(clientId);
        killSession(oldestSession);
    }
    sessionsPerUser.add(clientId, Integer.parseInt(userSession));
}

public void onHTTPCupertinoStreamingSessionDestroy(IHTTPStreamerSession httpSession) {
    String userSession = httpSession.getSessionId();
    // it’s easier to remove from map when we know both clientId and userSession
    String clientId = httpSession.getProperties().getPropertyStr("sql_client_id");
    //remove from hashmap, clientId based on session userSession
    sessionsPerUser.remove(clientId, Integer.parseInt(userSession));
}

// method name in camel case (like variable names)
public void killSession(int SessionId){ 
    IApplicationInstance Instance = applicationInstance;
    IHTTPStreamerSession sessions = Instance.getHTTPStreamerSessions().get(SessionId);
    sessions.rejectSession();
    //don’t remove from hashmap here, assume caller has done that
}

我将客户端 ID 存储为字符串,会话 ID 存储为整数。您可能希望对两者使用相同的类型。既然你已经用int 参数声明了KillSession(),我想我会在会话中使用int

【讨论】:

    猜你喜欢
    • 2021-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-26
    • 2016-06-05
    • 2011-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多