更新:问题后立即解决。
问题:
通常,同步是在 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) {
...
}
对此解决方案有何评论?
最佳答案
我在 spring-mvc 中找到了这个很好的解释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/