4

我看到很多关于 setAttribute 和 getAttribute 方法是否HttpSession是原子的问题。他们不是。但是,每个客户端的实际调用是request.getSession(true)原子的吗?

例如,如果您有一个 servlet 过滤器并且客户端发出两个同时到达一条线路request.getSession(true)的同时调用,是否会返回相同的会话对象?我认为这样的事情将是特定于容器的?或者您是否保证getSession每个请求客户的同步呼叫。

4

3 回答 3

6

不它不是。

Servlet 规范说……

2.3.3.4 线程安全 除了 startAsync 和 complete 方法,请求和响应对象的实现不保证是线程安全的。这意味着它们只能在请求处理线程的范围内使用,或者应用程序必须确保对请求和响应对象的访问是线程安全的。

如果应用程序创建的线程使用容器管理的对象,例如请求或响应对象,则必须仅在 3.10 和 5.6 节中定义的对象生命周期内访问这些对象。请注意,除了 startAsync 和 complete 方法,请求和响应对象不是线程安全的。如果这些对象是在多个线程中访问的,则应同步访问或通过包装器完成访问以添加线程安全性,例如例如,同步方法调用以访问请求属性,或使用本地输出流作为线程内的响应对象。

你的问题? 即使它们来自同一个客户端,两个对 getSession 的并发调用是否可能返回不同的 HttpSession 对象? 答案是“是的,

  • 它将返回两个会话对象,
  • 两个 Set-Cookies 将被发送到客户端
  • 最新的 Set-Cookie 可能会覆盖第一个
于 2013-01-03T13:34:21.713 回答
1

不确定您在这里真正关心的是什么:

例如,如果您有一个 servlet 过滤器,并且客户端发出两个同时到达线路的同时调用:

request.getSession(true)

会返回相同的会话对象吗?

这取决于你所说的同一个会话对象是什么意思,即你的意思是s1 == s2s1.equals(s2)。我找不到任何说明对象必须相同 ( ==) 的内容,但即使它们可能都是不同的对象,它们最终也可以看到相同的逻辑会话。将这些会话对象想象为数据库客户端:它们不是数据,但它们都查看相同的数据,即它们读取和写入到一个公共位置。

现在,要回答您的问题,我们必须在读取来自同一服务器的任何其他响应之前确定客户端是否发出了第二个请求:必须使用输入(在 URL 或 HTTP 标头中,在cookie 的形式),所以我们有以下场景:

  1. 客户端发出请求 #1,获取会话,并在两个同时请求 #2 和 #3 中将会话 ID 发送回服务器:它们将共享会话
  2. 客户端几乎同时发出请求#1 和#2,之前没有对同一个应用程序的任何请求。由于没有向服务器提供输入(没有会话 ID),因此创建了两个新会话,即使客户端没有同时点击 getSession() 行。根据客户端应用程序,这可能是错误,也可能不是。

所以这根本不是线程的问题。它仅取决于客户端提供的输入。相同的会话 ID,返回相同的会话。不同(或没有)会话 ID,不同的会话。

只是为了正确起见,一个逻辑客户端(单个程序,如 Firefox)甚至可以在 N+ 核机器上的 N 个单独线程中发出 N 个请求,但网络通常是共享的。假设它有一个多宿主机器,并且每个 NIC 都连接到一个单独的网络,您将需要您的 servlet 容器来监听多个 IP 地址并拥有 N 个处理器(或内核)。这只是说不需要同时进行两个调用,尽管来自同一个客户端的请求完全有可能并行处理并因此同时到达同一行。

于 2013-01-03T14:00:38.117 回答
0

API中没有任何内容表明该方法是同步的,尽管我不知道该方法内部发生了什么。getSession(true)如果不存在,Doing返回一个新会话。检查现有会话并创建新会话是您的关键部分。如果您的线程同时达到这一点,则将创建两个会话并将其返回给您的两个不同的调用实体(过滤器将在您的 servlet 之前和之后应用,因此我不知道您如何做到这一点,但是为了这个问题,让我们假设它可能发生)。如果一个Session对象已经存在,那么只会返回那个对象。

于 2013-01-03T14:19:35.200 回答