55

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

另外,我在网上阅读了一些建议使用的内容:

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

这是一个有效的建议吗?

4

5 回答 5

68

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 创建 mutex,但必须有更好的方法。

于 2009-03-05T21:34:53.830 回答
5

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

于 2009-03-05T21:22:50.317 回答
4

在某些方面,这取决于您的客户端设计。

在您的网页设计中,您是否有机会让单个客户端使用同一个 HTTP 会话同时处理多个未完成的请求?除非您将单个 HTTP 会话绑定到多个套接字,否则这似乎很难做到。(又名,AJAX)如果不这样做,就服务器而言,给定客户端的 HTTP 访问将是单线程的,这意味着单个会话实际上是线程安全的。

会话对象的同步将使应用程序更安全地应对未来的变化,使您的 Web 应用程序能够同时处理多个请求,所以这不是一个坏主意。在现代 Java 实现中,同步没有以前与之相关的大成本,尤其是当同步通常没有竞争时。如果您的应用程序使用 AJAX,这意味着您希望对 Web 服务器有多个正在进行的同时请求,那么同步是必须的。

于 2009-03-05T21:27:20.807 回答
2

它们不是,但大多数情况下,您的客户端只会使用单个线程访问它们。

不同的客户端会有不同的线程,每个都有自己的 Session。

正如 Eddie 所指出的,您可能面临两个线程访问同一会话的一种情况是两个 ajax 调用试图修改同一会话属性。否则你不会有问题。

于 2009-03-05T21:36:21.160 回答
1

会话不是线程安全的,get 和 set 方法都不能保证是线程安全的。通常,在 servlet 容器中,您应该假设处于多线程环境中,并且没有提供的工具是安全的。

这也适用于您存储在会话中的对象。会话本身不会操作存储的对象,但您可以在不同的线程中检索对象并尝试操作它。您可以检查自己的代码以查看是否可能出现竞争条件。

您发布的代码示例是有效的,但问题可能存在于您示例的有限范围之外。它确保在设置会话时没有条件,但没有什么能阻止其他线程覆盖该集合。如果您请求中的代码取决于保持不变的值,您仍然可能会遇到麻烦。

于 2009-03-05T21:27:27.140 回答