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

2022-08-31 17:37:40

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

另外,我在网上读到一些人建议使用:

synchronized(session) {
  session.setAttribute("abc", "abc");
}

这是一个有效的建议吗?


答案 1

Servlet 2.5 规范:

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

这是安全的:

// guaranteed by the spec to be safe
request.getSession().setAttribute("foo", 1);

这是不安全的

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);

不能保证是安全的:

// 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);
}

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


答案 2

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


推荐