bas*_*ero 30 java session multithreading synchronization servlets
更新:解决方案后问题.
通常,同步是在JVM内串行化并行请求,例如
private static final Object LOCK = new Object();
public void doSomething() {
...
synchronized(LOCK) {
...
}
...
}
Run Code Online (Sandbox Code Playgroud)
在查看Web应用程序时,"JVM全局"范围上的某些同步可能会成为性能瓶颈,仅在用户的HttpSession范围内进行同步会更有意义.
以下代码是否可能?我怀疑同步会话对象是一个好主意,但听到你的想法会很有趣.
HttpSession session = getHttpServletRequest().getSession();
synchronized (session) {
...
}
Run Code Online (Sandbox Code Playgroud)
关键问题:对于处理来自同一用户的请求的所有线程
,是否保证会话对象是同一个实例?
看来会话对象本身并不总是相同,它依赖于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;
}
Run Code Online (Sandbox Code Playgroud)
然后你可以使用它:
Object sessionLock = MyHelper.getSessionLock(getRequest(), null);
synchronized (sessionLock) {
...
}
Run Code Online (Sandbox Code Playgroud)
对此解决方案有何评论?
Tom*_*icz 30
我在spring-mvc JavaDoc中找到了这个很好的解释WebUtils.getSessionMutex():
在许多情况下,HttpSession引用本身也是一个安全的互斥锁,因为它始终是同一个活动逻辑会话的相同对象引用.但是,不能保证不同的servlet容器 ; 唯一100%安全的方式是会话互斥.
synchronizeOnSession设置标志时,此方法用作锁定:
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return handleRequestInternal(request, response);
}
Run Code Online (Sandbox Code Playgroud)
如果你看一下getSessionMutex()它的实现,它实际上使用了一些自定义会话属性(如果存在)(如果存在org.springframework.web.util.WebUtils.MUTEX)或HttpSession实例,如果不存在:
Object mutex = session.getAttribute(SESSION_MUTEX_ATTRIBUTE);
if (mutex == null) {
mutex = session;
}
return mutex;
Run Code Online (Sandbox Code Playgroud)
回到普通的servlet规范 - 100%确定使用自定义会话属性而不是HttpSession对象本身.
一般来说,不要依赖于HttpServletRequest.getSession()返回相同的对象.无论出于何种原因,servlet过滤器都很容易在会话中创建包装器.您的代码只会看到此包装器,并且每个请求都将是不同的对象.将一些共享锁放入会话本身.(太糟糕了,但没有putIfAbsent).
会话对象本身似乎并不总是相同,因为它取决于 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;
}
Run Code Online (Sandbox Code Playgroud)
然后你就可以使用它:
Object sessionLock = MyHelper.getSessionLock(getRequest(), null);
synchronized (sessionLock) {
...
}
Run Code Online (Sandbox Code Playgroud)
对此解决方案有何评论?
| 归档时间: |
|
| 查看次数: |
16993 次 |
| 最近记录: |