java - HttpSession 中的同步是否可行?

标签 java multithreading session servlets synchronization

更新:问题后立即解决。

问题:

通常,同步是在 JVM 中序列化并行请求,例如

private static final Object LOCK = new Object();

public void doSomething() {
  ...
  synchronized(LOCK) {
    ...
  }
  ...
}

在查看 Web 应用程序时,“JVM 全局”范围内的一些同步可能会成为性能瓶颈,并且只能在用户的 HttpSession 范围内进行同步。会更有意义。

下面的代码有可能吗?我怀疑在 session 对象上同步是一个好主意,但听听您的想法会很有趣。

HttpSession session = getHttpServletRequest().getSession();
synchronized (session) {
  ...
}

关键问题:
对于处理来自同一用户的请求的所有线程,是否保证 session 对象是相同的实例

总结答案/解决方案:

似乎 session 对象本身并不总是相同,因为它取决于 servlet 容器(Tomcat、Glassfish 等)的实现,并且 getSession() 方法可能只返回一个包装器实例。

因此建议使用存储在 session 中的自定义变量作为锁定对象。

这是我的代码建议,欢迎反馈:

在 Helper 类中的某处,例如我的助手:

private static final Object LOCK = new Object();

public static Object getSessionLock(HttpServletRequest request, String lockName) {
    if (lockName == null) lockName = "SESSION_LOCK";
    Object result = request.getSession().getAttribute(lockName);
    if (result == null) {
        // only if there is no session-lock object in the session we apply the global lock
        synchronized (LOCK) {
            // as it can be that another thread has updated the session-lock object in the meantime, we have to read it again from the session and create it only if it is not there yet!
            result = request.getSession().getAttribute(lockName);
            if (result == null) {
                result = new Object();
                request.getSession().setAttribute(lockName, result);
            }
        }
    }
    return result;
}

然后你就可以使用它了:

Object sessionLock = MyHelper.getSessionLock(getRequest(), null);
synchronized (sessionLock) {
  ...
}

对此解决方案有何评论?

最佳答案

我在 中找到了这个很好的解释WebUtils.getSessionMutex() 的 JavaDoc :

In many cases, the HttpSession reference itself is a safe mutex as well, since it will always be the same object reference for the same active logical session. However, this is not guaranteed across different servlet containers; the only 100% safe way is a session mutex.

当设置了 synchronizeOnSession 标志时,此方法用作锁:

Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
    return handleRequestInternal(request, response);
}

如果您查看 getSessionMutex() 的实现,它实际上使用了一些自定义 session 属性(如果存在)(在 org.springframework.web.util.WebUtils.MUTEX key) 或 HttpSession 实例,如果不是:

Object mutex = session.getAttribute(SESSION_MUTEX_ATTRIBUTE);
if (mutex == null) {
    mutex = session;
}
return mutex;

回到普通的 servlet 规范 - 100% 确定使用自定义 session 属性而不是 HttpSession 对象本身。

另见

关于java - HttpSession 中的同步是否可行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9802165/

相关文章:

java - 模拟 HttpHeaders 抛出 NullPointerException

java - Android创建没有源代码的库项目

c# - 来自非浏览器请求的 asp.net session 状态

PHP:在 $_SESSION 中存储 'objects'

javascript - 为什么在 javascript 中使用 fetch 后 session 会被清除?

java - 使用三元运算符在 spring 配置中传递参数

java - RESTEasy 客户端独立工作但在 Tomcat 中失败

.net - Interlocked.Exchange,但不适用于 bool 值?

python - 如何重构此代码以便不会发生 Pickle 'Buffer Region' 错误

c# - 为什么空白线程要占用 30% 的 CPU?