UPDATE:问题后立即解决。
问题:
通常,同步是在 JVM 内序列化并行请求,例如
private static final Object LOCK = new Object();
public void doSomething() {
...
synchronized(LOCK) {
...
}
...
}
在查看 Web 应用程序时,“JVM 全局”范围内的某些同步可能会成为性能瓶颈,并且仅在用户范围内进行同步Http会话 http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpSession.html会更有意义。
下面的代码可以吗?我怀疑同步会话对象是个好主意,但听听您的想法会很有趣。
HttpSession session = getHttpServletRequest().getSession();
synchronized (session) {
...
}
关键问题:
是否保证会话对象是同一个实例对于处理来自同一用户的请求的所有线程?
总结答案/解决方案:
看来会话对象本身并不总是相同的,因为它取决于servlet容器(Tomcat,Glassfish,...)的实现和getSession()
方法可能只返回一个包装器实例。
因此建议使用存储在会话中的自定义变量作为锁定对象。
这是我的代码建议,欢迎反馈:
助手类中的某个地方,例如MyHelper
:
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) {
...
}
对此解决方案有何评论?