问答中心分类: MULTITHREADINGservlet 是如何工作的?实例化、会话、共享变量和多线程
0
匿名用户 提问 6分钟 前

假设,我有一个包含许多 servlet 的网络服务器。对于在这些 servlet 之间传递的信息,我正在设置会话和实例变量。
现在,如果 2 个或更多用户向该服务器发送请求,那么会话变量会发生什么情况?
它们对所有用户都是通用的,还是对每个用户都不同?
如果它们不同,那么服务器如何区分不同的用户?
另一个类似的问题,如果有n用户访问特定的 servlet,那么这个 servlet 仅在第一个用户第一次访问它时才被实例化,还是单独为所有用户实例化?
换句话说,实例变量会发生什么?

7 Answers
0
Jops 回答 6分钟 前

会话
在此处输入图像描述
在此处输入图像描述
简而言之:Web 服务器向每位访客在他的第一的访问。访客必须带回该 ID,以便下次识别。此标识符还允许服务器正确地将一个会话拥有的对象与另一个会话拥有的对象隔离开来。
Servlet 实例化
如果启动时加载错误的
在此处输入图像描述
在此处输入图像描述
如果启动时加载真的
在此处输入图像描述
在此处输入图像描述
一旦他进入发球模式并进入凹槽,相同的servlet 将处理来自所有其他客户端的请求。
在此处输入图像描述
为什么每个客户端拥有一个实例不是一个好主意?想一想:你会为每一份订单雇佣一个披萨店员吗?这样做,你很快就会倒闭。
不过,它带来了很小的风险。记住:这个单身汉把所有的订单信息都放在口袋里:所以如果你不小心servlet 上的线程安全,他最终可能会向某个客户发出错误的订单。

zh18 回复 6分钟 前

你的照片很适合我的理解。我有一个问题,当披萨订单太多时,这家披萨店会怎么做,等一个披萨店员还是雇佣更多的披萨店员?谢谢 。

NaN 回复 6分钟 前

他会回复一条消息to many requests at this moment. try again later

bruno 回复 6分钟 前

Servlet 与 Pizza 送货员不同,它可以同时进行多个送货。他们只需要特别注意写下客户地址的位置,披萨的味道……

0
Chris Thompson 回答 6分钟 前

Java servlet 中的会话与 PHP 等其他语言中的会话相同。它是用户独有的。服务器可以通过不同的方式来跟踪它,例如 cookie、url 重写等。这Java 文档文章在 Java servlet 的上下文中对其进行了解释,并指出究竟如何维护会话是留给服务器设计者的实现细节。该规范仅规定它必须在与服务器的多个连接中对用户保持唯一性。查看这篇文章来自甲骨文有关您的两个问题的更多信息。
编辑有一个很棒的教程这里关于如何在 servlet 中使用 session。和这里是 Sun 关于 Java Servlet、它们是什么以及如何使用它们的一章。在这两篇文章之间,您应该能够回答所有问题。

Ku Jon 回复 6分钟 前

这给我带来了另一个问题,因为整个应用程序只有一个 servlet 上下文,我们可以通过这个 servlet 上下文访问会话变量,那么会话变量如何对每个用户都是唯一的?谢谢..

matt b 回复 6分钟 前

您如何从 servletContext 访问会话?您不是指 servletContext.setAttribute(),是吗?

Basil Bourque 回复 6分钟 前

@KuJon 每个网络应用程序都有一个ServletContext目的。该对象有零个、一个或多个会话对象——会话对象的集合。每个会话都由某种标识符字符串标识,如其他答案的漫画中所示。通过 cookie 或 URL 重写在客户端上跟踪该标识符。每个会话对象都有自己的变量。

0
Ajay Takur 回答 6分钟 前

当 servlet 容器(如 Apache Tomcat)启动时,如果出现任何问题或在容器端控制台显示错误,它将从 web.xml 文件中读取(每个应用程序只有一个),否则,它将部署并加载所有 web应用程序使用 web.xml(因此将其命名为部署描述符)。
在 servlet 的实例化阶段,servlet 实例已准备就绪,但它无法为客户端请求提供服务,因为它缺少两条信息:
1:上下文信息
2:初始配置信息
Servlet 引擎创建 servletConfig 接口对象,将上述缺失信息封装到其中 servlet 引擎通过提供 servletConfig 对象引用作为参数调用 servlet 的 init()。一旦 init() 完全执行,servlet 就准备好为客户端请求提供服务。
Q) 在 servlet 的生命周期中,实例化和初始化发生了多少次??
A) 仅一次(对于每个客户端请求,都会创建一个新线程)只有一个 servlet 实例服务于任意数量的客户端请求,即,在服务一个客户端请求后,服务器不会死机。它等待其他客户端请求,即 servlet(内部 servlet 引擎创建线程)克服了 CGI(为每个客户端请求创建一个新进程)限制。
Q) 会话概念如何运作?
A) 每当在 HttpServletRequest 对象上调用 getSession() 时
步骤1:请求对象评估传入会话 ID。
第2步:如果 ID 不可用,则创建一个全新的 HttpSession 对象并生成其对应的会话 ID(即 HashTable),将会话 ID 存储到 httpservlet 响应对象中,并将 HttpSession 对象的引用返回给 servlet(doGet/doPost)。
第 3 步: 如果 ID 可用,则未创建全新的会话对象,从请求对象中提取会话 ID,使用会话 ID 作为键在会话集合中进行搜索。
一旦搜索成功,会话 ID 就会存储到 HttpServletResponse 中,并且现有的会话对象引用会返回给 UserDefineservlet 的 doGet() 或 doPost()。
笔记:
1)当控制权从 servlet 代码转移到客户端时,不要忘记会话对象由 servlet 容器(即 servlet 引擎)持有
2)多线程留给servlet开发人员实现,即处理客户端的多个请求,无需担心多线程代码
简写形式:
servlet 在应用程序启动(部署在 servlet 容器上)或第一次访问(取决于 load-on-startup 设置)时创建 servlet 实例化时,调用 servlet 的 init() 方法然后 servlet(它的唯一实例)处理所有请求(它的 service() 方法被多个线程调用)。这就是为什么不建议在其中进行任何同步的原因,并且应避免在取消部署应用程序(servlet 容器停止)时调用 servlet 的实例变量,调用 destroy() 方法。

0
Lauri Lehtinen 回答 6分钟 前

会话– 克里斯汤普森说的话。
实例化– 当容器接收到映射到 servlet 的第一个请求时实例化 servlet(除非 servlet 配置为在启动时加载<load-on-startup>元素在web.xml)。相同的实例用于服务后续请求。

Basil Bourque 回复 6分钟 前

正确的。额外的想法:每个请求都有一个新的(或回收的)线程在该单个 Servlet 实例上运行。每个 Servlet 有一个实例,可能还有很多线程(如果有很多同时请求)。

0
tharindu_DG 回答 6分钟 前

Servlet 规范JSR-315明确定义服务(以及 doGet、doPost、doPut 等)方法中的 Web 容器行为(2.3.3.1 多线程问题,第 9 页):

servlet 容器可以通过 servlet 的 service 方法发送并发请求。为了处理请求,Servlet 开发人员必须为服务方法中的多个线程的并发处理做出足够的准备。
虽然不推荐,但开发者的替代方案是实现 SingleThreadModel 接口,该接口要求容器保证服务方法中一次只有一个请求线程。 servlet 容器可以通过序列化 servlet 上的请求或维护 servlet 实例池来满足此要求。如果 servlet 是已标记为可分发的 Web 应用程序的一部分,则容器可以在每个 JVM 中维护一个 servlet 实例池,该应用程序分布在该应用程序上。
对于没有实现 SingleThreadModel 接口的 servlet,如果服务方法(或分派给 HttpServlet 抽象类的服务方法的 doGet 或 doPost 等方法)已经用 synchronized 关键字定义,则 servlet 容器不能使用实例池方式,但必须通过它序列化请求。强烈建议开发人员不要在这些情况下同步服务方法(或分派给它的方法),因为这会对性能产生不利影响

Basil Bourque 回复 6分钟 前

仅供参考,当前的 Servlet 规范(2015-01)是 3.1,定义为JSR 340.

Tom Taylor 回复 6分钟 前

非常整洁的答案! @tharindu_DG