【问题标题】:how to safely store hashmap in httpsession in java如何在java中的httpsession中安全地存储hashmap
【发布时间】:2017-12-20 20:23:43
【问题描述】:

如果我在 httpsession 中存储并发 hashmap,那么如何以线程安全的方式使用这个 hashmap?使用 hashmap 是指以线程安全的方式添加和检索 hashmap。

在获取/放入此哈希图时我应该锁定什么对象?

这段代码好吗:

private static final String SESSION_KEY_USER_IDENT = "CloudIdentityUserListMap";

private someSessionPopulateFunc()
{
    final Object lock = sess.getHttpSession().getId().intern();
    ConcurrentHashMap<String, List<User>> cloudIdentityUserListMap;
    if (sess.getAttribute(SESSION_KEY_USER_IDENT) != null) {
        synchronized (lock) {
            cloudIdentityUserListMap = (ConcurrentHashMap<String, List<User>>) sess.getAttribute(SESSION_KEY_USER_IDENT);
        }
    } else {
        cloudIdentityUserListMap = new ConcurrentHashMap<String, List<User>>();
        synchronized (lock) {
            sess.setAttribute (SESSION_KEY_USER_IDENT, cloudIdentityUserListMap);
        }
    }
    cloudIdentityUserListMap.putIfAbsent(cloudIdentity,users);
}

在从这个 concurrenthashmap 读取值时,我是否需要再次获取 sess.getHttpSession().getId().intern() 的锁定?

【问题讨论】:

  • 更重要的是,这张地图的并发用户是谁?您真的期望同一个会话有多个并发使用吗?
  • ConcurrentHashMap 存储在HttpSession 中的原因是什么?那有什么用例?整个构造只能在单个 JVM 或单个 Web 上下文中工作。使用 session id 的内部对象是脆弱的。关于您的问题,如果您需要从哈希图中查找。答案是不。这里有趣的是您如何访问值/在哪个上下文中以及当会话被序列化/反序列化时会发生什么。想想你是否真的需要这个结构,为什么以及是否可以通过其他方式解决。
  • 所以对于我的用例,我将只填充一次哈希图,然后从中读取...一旦填充了哈希图,无论如何都不会被操纵...我担心的是,虽然填充哈希图可能存在竞争条件,因为来自同一用户的 2 个或更多请求将访问同一个会话对象...
  • 同一个用户会同时出现在两个不同的页面上?
  • @EJP 这并不一定意味着这些是不同的页面,只是想一个单页 Web 应用程序,它对服务器端进行大量调用。

标签: java servlets concurrenthashmap httpsession


【解决方案1】:

来自 Java Servlet 规范 3.0:

7.7.1 线程问题

执行请求线程的多个 servlet 可以对同一个线程进行主动访问 同时会话对象。容器必须确保操纵 表示会话属性的内部数据结构在线程中执行 安全的方式。开发人员负责线程安全地访问 属性对象本身。这将保护内部的属性集合 HttpSession 对象从并发访问,消除了一个机会 应用程序导致该集合损坏。

然而HttpSession 一个哈希映射。很难理解为什么你需要一个嵌套的。

ConcurrentHashMap 也已经是线程安全的。

【讨论】:

  • 我有一个复杂的数据结构,它有一个哈希图......我将这个数据结构存储在会话中......因为将它存储到会话中将是线程安全的,所以我并不担心。 ...我担心的是以线程安全的方式操作数据结构内的映射....
  • 好的,所以从地图中读取也许我不需要任何锁,但是在将地图存储在会话中时,我应该在存储之前在会话上同步,对吗?否则可能会有多个请求尝试将此地图存储在会话中...
  • 不,因为我已经引用了 Servlet 规范 #7.7.1。这里的一切都是线程安全的。你不必做任何事情。
  • 谢谢,听起来不错;只是出于好奇,如果这个哈希映射在另一个对象中并且这个对象存储在会话中会发生什么,在这种情况下,当我对映射做任何事情时,我需要一个锁吗?因为 servlet 规范说开发人员需要访问存储在会话线程中的对象安全......对于这个用例,我应该使用 sess.getHttpSession().getId().intern() 来锁定吗?
  • 如前所述,使用getId().intern() 是危险的,原因有很多。参见例如here。为什么不使用绝对有效的东西,例如专用锁对象、信号量、队列或...?
猜你喜欢
  • 2011-08-11
  • 1970-01-01
  • 1970-01-01
  • 2014-09-19
  • 2012-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多