【发布时间】:2010-10-11 14:57:53
【问题描述】:
另外,被设置的对象是否必须是线程安全的,以保证我们知道存储在会话中的对象的状态是什么。
另外,我在网上阅读了一些建议使用的内容:
synchronized(session) {
session.setAttribute("abc", "abc");
}
这是一个有效的建议吗?
【问题讨论】:
标签: java session thread-safety synchronized
另外,被设置的对象是否必须是线程安全的,以保证我们知道存储在会话中的对象的状态是什么。
另外,我在网上阅读了一些建议使用的内容:
synchronized(session) {
session.setAttribute("abc", "abc");
}
这是一个有效的建议吗?
【问题讨论】:
标签: java session thread-safety synchronized
没有。而且由于您不希望同一个客户端(带有会话)进行并发请求,因此您应该像 AbstractController 在 Spring MVC 中那样序列化这些请求
【讨论】:
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 规范不能保证它可以工作。你可以use the session ID to create a mutex,但必须有更好的方法。
【讨论】:
this 上同步。也就是说,具有public syncrhonized void setAttribute... 或...setAttribute(String s,Object o) { synchronized(this)... 之类的签名。规范不需要这个。一些 servlet 容器会这样做,但不能保证 - 容器如何保护内部状态是一个实现细节。
它们不是,但大多数情况下,您的客户端只会使用单个线程访问它们。
不同的客户端会有不同的线程,每一个都会有自己的Session。
正如 Eddie 所指出的,您可能面临两个线程访问同一会话的一种情况是两个 ajax 调用试图修改同一会话属性。否则你不会有问题。
【讨论】:
会话不是线程安全的,get 和 set 方法都不能保证是线程安全的。通常,在 servlet 容器中,您应该假设处于多线程环境中,并且没有提供的工具是安全的。
这也适用于您存储在会话中的对象。会话本身不会操作存储的对象,但您可以在不同的线程中检索对象并尝试操作它。您可以检查自己的代码以查看是否存在竞争条件。
您发布的代码示例是有效的,但问题可能存在于您示例的有限范围之外。它确保在设置会话时没有条件,但没有什么可以阻止其他线程覆盖该集合。如果您请求中的代码取决于保持不变的值,您仍然可能遇到麻烦。
【讨论】:
在某些方面,这取决于您的客户端设计。
在您的网页设计中,您是否有机会让单个客户端使用同一个 HTTP 会话同时处理多个未完成的请求?除非您将单个 HTTP 会话绑定到多个套接字,否则这似乎很难做到。 (又名 AJAX)如果不这样做,就服务器而言,给定客户端的 HTTP 访问将是单线程的,这意味着单个会话实际上是线程安全的。
会话对象的同步将使应用程序更安全地应对未来的变化,使您的网络应用程序能够同时处理多个请求,所以这不是一个坏主意。在现代 Java 实现中,同步没有以前与之相关的大成本,尤其是当同步通常没有竞争时。如果您的应用程序使用 AJAX,这意味着您希望对 Web 服务器有多个正在进行的同时请求,那么同步是必须的。
【讨论】: