HttpSession线程是否安全,是否设置/获取属性线程安全操作?

Ber*_*own 53 java session synchronized thread-safety

此外,正在设置的对象是否必须是线程安全的,以保证我们知道会话中存储的对象的状态是什么.

此外,我正在网上阅读一些建议使用:

synchronized(session) {
  session.setAttribute("abc", "abc");
}
Run Code Online (Sandbox Code Playgroud)

这是一个有效的建议吗?

McD*_*ell 63

Servlet 2.5规范:

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

这很安全:

// guaranteed by the spec to be safe
request.getSession().setAttribute("foo", 1);
Run Code Online (Sandbox Code Playgroud)

这是不是安全的:

HttpSession session = request.getSession();
Integer n = (Integer) session.getAttribute("foo");
// not thread safe
// another thread might be have got stale value between get and set
session.setAttribute("foo", (n == null) ? 1 : n + 1);
Run Code Online (Sandbox Code Playgroud)

保证是安全的:

// no guarantee that same instance will be returned,
// nor that session will lock on "this"
HttpSession session = request.getSession();
synchronized (session) {
  Integer n = (Integer) session.getAttribute("foo");
  session.setAttribute("foo", (n == null) ? 1 : n + 1);
}
Run Code Online (Sandbox Code Playgroud)

我已经看到了最后提出的方法(包括在J2EE书籍中),但不保证它可以通过Servlet规范工作.您可以使用会话ID创建互斥锁,但必须有更好的方法.

  • 顺便说一句 - 对于"为什么会话对象上的同步可能不起作用"这一问题的正确答案是请求包装.无法保证您可能得到什么对象.任何人都可以创建请求包装器,它将返回自己的HttpSession实现(例如,一个日志记录或控制set/get,...). (2认同)

duf*_*ymo 37

不,它们不是线程安全的,根据IBM - Java理论和实践:所有有状态的Web应用程序都被破坏了吗?.你需要同步.

HttpSession如何不受Java Ranch的线程安全可能也有帮助.

  • 原始文章的链接已损坏(非常感谢 IBM)。我在其他任何地方都找不到托管。只有回程机可以帮助我。这是链接:http://web.archive.org/web/20110806042745/http://www.ibm.com/developerworks/java/library/j-jtp09238/index.html。 (2认同)

che*_*vim 5

不。并且由于您不希望同一个客户端(带有会话)执行并发请求,因此您应该像Spring MVC 中的AbstractController那样序列化这些请求