Java servlet 是如何工作的?实例化、会话、共享变量和多线程
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3106452/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do servlets work? Instantiation, sessions, shared variables and multithreading
提问by Ku Jon
Suppose, I have a webserver which holds numerous servlets. For information passing among those servlets I am setting session and instance variables.
假设,我有一个包含许多 servlet 的网络服务器。对于在这些 servlet 之间传递的信息,我正在设置会话和实例变量。
Now, if 2 or more users send request to this server then what happens to the session variables?
Will they all be common for all the users or they will be different for each user?
If they are different, then how was the server able to differentiate between different users?
现在,如果有 2 个或更多用户向该服务器发送请求,那么会话变量会发生什么变化?
它们对所有用户都是通用的还是对每个用户都不同?
如果它们不同,那么服务器如何区分不同的用户?
One more similar question, if there are n
users accessing a particular servlet, then this servlet gets instantiated only the first time the first user accessed it or does it get instantiated for all the users separately?
In other words, what happens to the instance variables?
还有一个类似的问题,如果有n
用户访问一个特定的 servlet,那么这个 servlet 只在第一个用户第一次访问它时被实例化,还是单独为所有用户实例化?
换句话说,实例变量会发生什么?
采纳答案by BalusC
ServletContext
服务端上下文
When the servlet container (like Apache Tomcat) starts up, it will deploy and load all its web applications. When a web application is loaded, the servlet container creates the ServletContext
once and keeps it in the server's memory. The web app's web.xml
and all of included web-fragment.xml
files is parsed, and each <servlet>
, <filter>
and <listener>
found (or each class annotated with @WebServlet
, @WebFilter
and @WebListener
respectively) is instantiated once and kept in the server's memory as well. For each instantiated filter, its init()
method is invoked with a new FilterConfig
.
当 servlet 容器(如Apache Tomcat)启动时,它将部署和加载所有 Web 应用程序。加载 Web 应用程序时,servlet 容器会创建ServletContext
一次并将其保存在服务器的内存中。Web 应用程序web.xml
和所有包含的web-fragment.xml
文件都被解析,并且每个<servlet>
,<filter>
和<listener>
found (或每个类分别用@WebServlet
,@WebFilter
和注释@WebListener
)被实例化一次并保存在服务器的内存中。对于每个实例化的过滤器,它的init()
方法被调用一个新的FilterConfig
.
When a Servlet
has a <servlet><load-on-startup>
or @WebServlet(loadOnStartup)
value greater than 0
, then its init()
method is also invoked during startup with a new ServletConfig
. Those servlets are initialized in the same order specified by that value (1
is 1st, 2
is 2nd, etc). If the same value is specified for more than one servlet, then each of those servlets is loaded in the same order as they appear in the web.xml
, web-fragment.xml
, or @WebServlet
classloading. In the event the "load-on-startup" value is absent, the init()
method will be invoked whenever the HTTP request hits that servlet for the very first time.
当 aServlet
的<servlet><load-on-startup>
或@WebServlet(loadOnStartup)
值大于 时0
,它的init()
方法也会在启动期间使用 new 调用ServletConfig
。这些 servlet 以该值指定的相同顺序初始化(1
是 1st,2
是 2nd,等等)。如果多于一个的servlet指定了相同的值,则每个这些小服务程序的如它们出现在加载以相同的顺序web.xml
,web-fragment.xml
或@WebServlet
类加载。如果“load-on-startup”值不存在,则init()
只要 HTTP 请求第一次命中该 servlet,就会调用该方法。
When the servlet container is finished with all of the above described initialization steps, then the ServletContextListener#contextInitialized()
will be invoked.
当 servlet 容器完成上述所有初始化步骤后,ServletContextListener#contextInitialized()
将调用 。
When the servlet container shuts down, it unloads all web applications, invokes the destroy()
method of all its initialized servlets and filters, and all ServletContext
, Servlet
, Filter
and Listener
instances are trashed. Finally the ServletContextListener#contextDestroyed()
will be invoked.
当servlet容器关闭时,它卸载所有Web应用程序,调用destroy()
其全部初始化servlet和过滤器,所有的方法ServletContext
,Servlet
,Filter
和Listener
实例丢弃。最后ServletContextListener#contextDestroyed()
将被调用。
HttpServletRequest and HttpServletResponse
HttpServletRequest 和 HttpServletResponse
The servlet container is attached to a web server that listens for HTTP requests on a certain port number (port 8080 is usually used during development and port 80 in production). When a client (e.g. user with a web browser, or programmatically using URLConnection
) sends an HTTP request, the servlet container creates new HttpServletRequest
and HttpServletResponse
objects and passes them through any defined Filter
in the chain and, eventually, the Servlet
instance.
servlet 容器附加到一个 web 服务器上,该服务器在某个端口号上侦听 HTTP 请求(端口 8080 通常在开发期间使用,端口 80 在生产中使用)。当客户端(例如,使用 Web 浏览器或以编程方式使用 的用户URLConnection
)发送 HTTP 请求时,servlet 容器会创建新的HttpServletRequest
和HttpServletResponse
对象,并将它们传递给Filter
链中定义的任何对象,最终传递给Servlet
实例。
In the case of filters, the doFilter()
method is invoked. When the servlet container's code calls chain.doFilter(request, response)
, the request and response continue on to the next filter, or hit the servlet if there are no remaining filters.
在过滤器的情况下,该doFilter()
方法被调用。当 servlet 容器的代码调用 时chain.doFilter(request, response)
,请求和响应继续到下一个过滤器,如果没有剩余的过滤器,则命中 servlet。
In the case of servlets, the service()
method is invoked. By default, this method determines which one of the doXxx()
methods to invoke based off of request.getMethod()
. If the determined method is absent from the servlet, then an HTTP 405 error is returned in the response.
在servlets的情况下,该service()
方法被调用。默认情况下,此方法根据 确定doXxx()
要调用的方法之一 request.getMethod()
。如果 servlet 中不存在确定的方法,则响应中将返回 HTTP 405 错误。
The request object provides access to all of the information about the HTTP request, such as its URL, headers, query string and body. The response object provides the ability to control and send the HTTP response the way you want by, for instance, allowing you to set the headers and the body (usually with generated HTML content from a JSP file). When the HTTP response is committed and finished, both the request and response objects are recycled and made available for reuse.
request 对象提供对有关 HTTP 请求的所有信息的访问,例如其 URL、标头、查询字符串和正文。响应对象提供了以您想要的方式控制和发送 HTTP 响应的能力,例如,允许您设置标题和正文(通常使用从 JSP 文件生成的 HTML 内容)。当 HTTP 响应提交并完成时,请求和响应对象都会被回收并可供重用。
HttpSession
HttpSession
When a client visits the webapp for the first time and/or the HttpSession
is obtained for the first time via request.getSession()
, the servlet container creates a new HttpSession
object, generates a long and unique ID (which you can get by session.getId()
), and stores it in the server's memory. The servlet container also sets a Cookie
in the Set-Cookie
header of the HTTP response with JSESSIONID
as its name and the unique session ID as its value.
当客户端第一次访问 webapp 和/或HttpSession
第一次通过 获取 时request.getSession()
,servlet 容器会创建一个新HttpSession
对象,生成一个长而唯一的 ID(您可以通过 获取session.getId()
),并将其存储在服务器的记忆。servlet 容器还在HTTP 响应Cookie
的Set-Cookie
标头中设置 aJSESSIONID
作为其名称和唯一会话 ID 作为其值。
As per the HTTP cookie specification(a contract any decent web browser and web server must adhere to), the client (the web browser) is required to send this cookie back in subsequent requests in the Cookie
header for as long as the cookie is valid (i.e. the unique ID must refer to an unexpired session and the domain and path are correct). Using your browser's built-in HTTP traffic monitor, you can verify that the cookie is valid (press F12 in Chrome / Firefox 23+ / IE9+, and check the Net/Networktab). The servlet container will check the Cookie
header of every incoming HTTP request for the presence of the cookie with the name JSESSIONID
and use its value (the session ID) to get the associated HttpSession
from server's memory.
根据HTTP cookie 规范(任何体面的 Web 浏览器和 Web 服务器都必须遵守的合同),Cookie
只要 cookie 有效,客户端(Web 浏览器)就必须在标头中的后续请求中将此 cookie 发送回(即唯一 ID 必须指代未过期的会话,并且域和路径是正确的)。使用浏览器的内置 HTTP 流量监视器,您可以验证 cookie 是否有效(在 Chrome / Firefox 23+ / IE9+ 中按 F12,并检查网络/网络选项卡)。servlet 容器将检查Cookie
每个传入 HTTP 请求的标头是否存在带有名称的 cookie,JSESSIONID
并使用其值(会话 ID)HttpSession
从服务器的内存中获取相关联。
The HttpSession
stays alive until it has been idle (i.e. not used in a request) for more than the timeout value specified in <session-timeout>
, a setting in web.xml
. The timeout value defaults to 30 minutes. So, when the client doesn't visit the web app for longer than the time specified, the servlet container trashes the session. Every subsequent request, even with the cookie specified, will not have access to the same session anymore; the servlet container will create a new session.
的HttpSession
活,直到它停留已经空闲(即,在请求未使用)超过规定的超时值<session-timeout>
,在设定web.xml
。超时值默认为 30 分钟。因此,当客户端没有超过指定的时间访问 Web 应用程序时,servlet 容器会破坏会话。每个后续请求,即使指定了 cookie,也将无法再访问同一个会话;servlet 容器将创建一个新会话。
On the client side, the session cookie stays alive for as long as the browser instance is running. So, if the client closes the browser instance (all tabs/windows), then the session is trashed on the client's side. In a new browser instance, the cookie associated with the session wouldn't exist, so it would no longer be sent. This causes an entirely new HttpSession
to be created, with an entirely new session cookie being used.
在客户端,只要浏览器实例正在运行,会话 cookie 就会保持活动状态。因此,如果客户端关闭浏览器实例(所有选项卡/窗口),则会话在客户端被丢弃。在新的浏览器实例中,与会话关联的 cookie 将不存在,因此将不再发送。这会导致HttpSession
创建一个全新的会话 cookie,并使用一个全新的会话 cookie。
In a nutshell
简而言之
- The
ServletContext
lives for as long as the web app lives. It is shared among allrequests in allsessions. - The
HttpSession
lives for as long as the client is interacting with the web app with the same browser instance, and the session hasn't timed out at the server side. It is shared among allrequests in the samesession. - The
HttpServletRequest
andHttpServletResponse
live from the time the servlet receives an HTTP request from the client, until the complete response (the web page) has arrived. It is notshared elsewhere. - All
Servlet
,Filter
andListener
instances live as long as the web app lives. They are shared among allrequests in allsessions. - Any
attribute
that is defined inServletContext
,HttpServletRequest
andHttpSession
will live as long as the object in question lives. The object itself represents the "scope" in bean management frameworks such as JSF, CDI, Spring, etc. Those frameworks store their scoped beans as anattribute
of its closest matching scope.
- 的
ServletContext
生活,只要Web应用程序的生命。它在所有会话中的所有请求之间共享。 - 的
HttpSession
生活,只要客户端与同一个浏览器实例中的Web应用程序进行交互,和会话未在服务器端超时。它在同一会话中的所有请求之间共享。 - 在
HttpServletRequest
和HttpServletResponse
现场从servlet接收来自客户端的HTTP请求的时间,直到完全缓解(网页)已经到来。它不在其他地方共享。 - 所有
Servlet
,Filter
和Listener
实例只要 Web 应用程序存在就存在。它们在所有会话中的所有请求之间共享。 - 任何
attribute
被定义ServletContext
,HttpServletRequest
并且HttpSession
只要将生活中的问题生活中的对象。对象本身代表了 bean 管理框架(如 JSF、CDI、Spring 等)中的“范围”。这些框架将它们的作用域 bean 存储attribute
为与其最接近的匹配范围。
Thread Safety
线程安全
That said, your major concern is possibly thread safety. You should now know that servlets and filters are shared among all requests. That's the nice thing about Java, it's multithreaded and different threads (read: HTTP requests) can make use of the same instance. It would otherwise be too expensive to recreate, init()
and destroy()
them for every single request.
也就是说,您主要关心的可能是线程安全。您现在应该知道 servlet 和过滤器在所有请求之间共享。这就是 Java 的优点,它是多线程的,不同的线程(阅读:HTTP 请求)可以使用同一个实例。否则重新创建它们会太昂贵,init()
并且destroy()
为每个请求重新创建它们。
You should also realize that you should neverassign any request or session scoped data as an instancevariable of a servlet or filter. It will be shared among all other requests in other sessions. That's notthread-safe! The below example illustrates this:
您还应该意识到您永远不应该将任何请求或会话范围的数据分配为servlet 或过滤器的实例变量。它将在其他会话中的所有其他请求中共享。那不是线程安全的!下面的例子说明了这一点:
public class ExampleServlet extends HttpServlet {
private Object thisIsNOTThreadSafe;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object thisIsThreadSafe;
thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests!
thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe.
}
}
See also:
也可以看看:
回答by Chris Thompson
Session in Java servlets is the same as session in other languages such as PHP. It is unique to the user. The server can keep track of it in different ways such as cookies, url rewriting etc. This Java docarticle explains it in the context of Java servlets and indicates that exactly how session is maintained is an implementation detail left to the designers of the server. The specification only stipulates that it must be maintained as unique to a user across multiple connections to the server. Check out this article from Oraclefor more information about both of your questions.
Java servlet 中的会话与其他语言(如 PHP)中的会话相同。它对用户来说是独一无二的。服务器可以通过不同的方式跟踪它,例如 cookie、url 重写等。这篇Java 文档文章在 Java servlet 的上下文中解释了它,并指出究竟如何维护会话是留给服务器设计者的一个实现细节。该规范仅规定它必须在与服务器的多个连接中对用户保持唯一。查看Oracle 的这篇文章,了解有关您的两个问题的更多信息。
EditThere is an excellent tutorial hereon how to work with session inside of servlets. And hereis a chapter from Sun about Java Servlets, what they are and how to use them. Between those two articles, you should be able to answer all of your questions.
编辑有一个很好的教程在这里就如何使用Servlet的会话内不起作用。而这里是来自Sun关于Java Servlet的,它们是什么,以及如何使用它们的一章。在这两篇文章之间,您应该能够回答所有问题。
回答by Lauri Lehtinen
Sessions- what Chris Thompson said.
Sessions- Chris Thompson 所说的。
Instantiation- a servlet is instantiated when the container receives the first request mapped to the servlet (unless the servlet is configured to load on startup with the <load-on-startup>
element in web.xml
). The same instance is used to serve subsequent requests.
实例化- 当容器接收到映射到 servlet 的第一个请求时实例化一个 servlet(除非 servlet 被配置为在启动时加载 中的<load-on-startup>
元素web.xml
)。相同的实例用于为后续请求提供服务。
回答by Ajay Takur
When the servlet container (like Apache Tomcat) starts up, it will read from the web.xml file (only one per application) if anything goes wrong or shows up an error at container side console, otherwise, it will deploy and load all web applications by using web.xml (so named it as deployment descriptor).
当 servlet 容器(如 Apache Tomcat)启动时,如果出现任何问题或在容器侧控制台显示错误,它将从 web.xml 文件(每个应用程序只读取一个)中读取,否则,它将部署并加载所有 web应用程序使用 web.xml(因此将其命名为部署描述符)。
During instantiation phase of the servlet, servlet instance is ready but it cannot serve the client request because it is missing with two pieces of information:
1: context information
2: initial configuration information
在 servlet 的实例化阶段,servlet 实例已准备就绪,但它无法为客户端请求提供服务,因为它缺少两条信息:
1:上下文信息
2:初始配置信息
Servlet engine creates servletConfig interface object encapsulating the above missing information into it servlet engine calls init() of the servlet by supplying servletConfig object references as an argument. Once init() is completely executed servlet is ready to serve the client request.
servlet 引擎创建 servletConfig 接口对象,将上述缺失信息封装到其中 servlet 引擎通过提供 servletConfig 对象引用作为参数来调用 servlet 的 init()。一旦 init() 完全执行,servlet 就准备好为客户端请求提供服务。
Q) In the lifetime of servlet how many times instantiation and initialization happens ??
Q) 在 servlet 的生命周期中发生了多少次实例化和初始化??
A)only once (for every client request a new thread is created) only one instance of the servlet serves any number of the client request ie, after serving one client request server does not die. It waits for other client requests ie what CGI (for every client request a new process is created) limitation is overcome with the servlet (internally servlet engine creates the thread).
A)只有一次(为每个客户端请求创建一个新线程)只有一个 servlet 实例服务于任意数量的客户端请求,即在服务一个客户端请求后,服务器不会死。它等待其他客户端请求,即什么 CGI(为每个客户端请求创建一个新进程)限制被 servlet 克服(在内部 servlet 引擎创建线程)。
Q)How session concept works?
问)会话概念如何运作?
A)whenever getSession() is called on HttpServletRequest object
A) 每当在 HttpServletRequest 对象上调用 getSession() 时
Step 1: request object is evaluated for incoming session ID.
步骤 1:针对传入会话 ID 评估请求对象。
Step 2: if ID not available a brand new HttpSession object is created and its corresponding session ID is generated (ie of HashTable) session ID is stored into httpservlet response object and the reference of HttpSession object is returned to the servlet (doGet/doPost).
步骤 2:如果 ID 不可用,则创建一个全新的 HttpSession 对象并生成其对应的会话 ID(即 HashTable)会话 ID 存储到 httpservlet 响应对象中,并将 HttpSession 对象的引用返回给 servlet(doGet/doPost) .
Step 3: if ID available brand new session object is not created session ID is picked up from the request object search is made in the collection of sessions by using session ID as the key.
步骤3:如果ID可用,则未创建全新的会话对象,从请求对象中提取会话ID,使用会话ID作为关键字在会话集合中进行搜索。
Once the search is successful session ID is stored into HttpServletResponse and the existing session object references are returned to the doGet() or doPost() of UserDefineservlet.
一旦搜索成功,会话 ID 就会存储到 HttpServletResponse 中,并且现有的会话对象引用将返回给 UserDefineservlet 的 doGet() 或 doPost()。
Note:
笔记:
1)when control leaves from servlet code to client don't forget that session object is being held by servlet container ie, the servlet engine
1) 当控制权从 servlet 代码转移到客户端时,不要忘记 servlet 容器即 servlet 引擎持有会话对象
2)multithreading is left to servlet developers people for implementing ie., handle the multiple requests of client nothing to bother about multithread code
2)多线程留给servlet开发人员来实现,即处理客户端的多个请求,无需担心多线程代码
Inshort form:
简写形式:
A servlet is created when the application starts (it is deployed on the servlet container) or when it is first accessed (depending on the load-on-startup setting) when the servlet is instantiated, the init() method of the servlet is called then the servlet (its one and only instance) handles all requests (its service() method being called by multiple threads). That's why it is not advisable to have any synchronization in it, and you should avoid instance variables of the servlet when the application is undeployed (the servlet container stops), the destroy() method is called.
servlet 在应用程序启动时(部署在 servlet 容器上)或首次访问时(取决于 load-on-startup 设置)在 servlet 实例化时创建,调用 servlet 的 init() 方法然后 servlet(它的唯一实例)处理所有请求(它的 service() 方法被多个线程调用)。这就是为什么不建议在其中进行任何同步的原因,并且在取消部署应用程序(servlet 容器停止)、调用 destroy() 方法时应避免使用 servlet 的实例变量。
回答by Jops
Sessions
会话
In short: the web server issues a unique identifier to each visitoron his firstvisit. The visitor must bring back that ID for him to be recognised next time around. This identifier also allows the server to properly segregate objects owned by one session against that of another.
简而言之:Web 服务器在每个访问者的第一次访问时为其发出一个唯一标识符。访客必须带回那个 ID 以便他下次被识别。此标识符还允许服务器将一个会话拥有的对象与另一个会话拥有的对象正确隔离。
Servlet Instantiation
Servlet 实例化
If load-on-startupis false:
如果load-on-startup为false:
If load-on-startupis true:
如果load-on-startup为true:
Once he's on the service mode and on the groove, the sameservlet will work on the requests from all other clients.
一旦他处于服务模式和凹槽,同一个servlet 将处理来自所有其他客户端的请求。
Why isn't it a good idea to have one instance per client? Think about this: Will you hire one pizza guy for every order that came? Do that and you'd be out of business in no time.
为什么每个客户端有一个实例不是一个好主意?想一想:你会为每一份订单雇佣一个披萨店员吗?这样做,你很快就会倒闭。
It comes with a small risk though. Remember: this single guy holds all the order information in his pocket: so if you're not cautious about thread safety on servlets, he may end up giving the wrong order to a certain client.
不过,它带来的风险很小。记住:这个人把所有的订单信息都放在口袋里:所以如果你对 servlet 的线程安全不谨慎,他可能最终会向某个客户端发出错误的订单。
回答by tharindu_DG
The Servlet Specification JSR-315clearly defines the web container behavior in the service (and doGet, doPost, doPut etc.) methods (2.3.3.1 Multithreading Issues, Page 9):
Servlet 规范JSR-315明确定义了服务(以及 doGet、doPost、doPut 等)方法中的 Web 容器行为(2.3.3.1 多线程问题,第 9 页):
A servlet container may send concurrent requests through the service method of the servlet. To handle the requests, the Servlet Developer must make adequate provisions for concurrent processing with multiple threads in the service method.
Although it is not recommended, an alternative for the Developer is to implement the SingleThreadModel interface which requires the container to guarantee that there is only one request thread at a time in the service method. A servlet container may satisfy this requirement by serializing requests on a servlet, or by maintaining a pool of servlet instances. If the servlet is part of a Web application that has been marked as distributable, the container may maintain a pool of servlet instances in each JVM that the application is distributed across.
For servlets not implementing the SingleThreadModel interface, if the service method (or methods such as doGet or doPost which are dispatched to the service method of the HttpServlet abstract class) has been defined with the synchronized keyword, the servlet container cannot use the instance pool approach, but must serialize requests through it. It is strongly recommended that Developers not synchronize the service method (or methods dispatched to it) in these circumstances because of detrimental effects on performance
servlet 容器可以通过 servlet 的 service 方法发送并发请求。为了处理请求,Servlet 开发人员必须为服务方法中的多线程并发处理做出足够的准备。
虽然不推荐,但对于开发者来说,另一种选择是实现 SingleThreadModel 接口,该接口要求容器保证服务方法中一次只有一个请求线程。servlet 容器可以通过在 servlet 上序列化请求或通过维护 servlet 实例池来满足此要求。如果 servlet 是已标记为可分发的 Web 应用程序的一部分,则容器可能会在应用程序分布的每个 JVM 中维护一个 servlet 实例池。
对于没有实现 SingleThreadModel 接口的 servlet,如果 service 方法(或分发到 HttpServlet 抽象类的 service 方法的 doGet 或 doPost 等方法)已经定义了 synchronized 关键字,则 servlet 容器不能使用实例池方式,但必须通过它序列化请求。强烈建议开发人员不要在这些情况下同步服务方法(或分派给它的方法),因为这会对性能产生不利影响
回答by Ved Prakash
No.Servlets are not Thread safe
不。Servlet不是线程安全的
This is allows accessing more than one threads at a time
这允许一次访问多个线程
if u want to make it Servlet as Thread safe ., U can go for
如果你想让它成为线程安全的 Servlet,你可以去
Implement SingleThreadInterface(i)
which is a blank Interface there is no
Implement SingleThreadInterface(i)
这是一个空白的界面,没有
methods
方法
or we can go for synchronize methods
或者我们可以去同步方法
we can make whole service method as synchronized by using synchronized
我们可以通过使用 synchronized 使整个服务方法同步
keyword in front of method
方法前的关键字
Example::
例子::
public Synchronized class service(ServletRequest request,ServletResponse response)throws ServletException,IOException
or we can the put block of the code in the Synchronized block
或者我们可以将代码的 put 块放在 Synchronized 块中
Example::
例子::
Synchronized(Object)
{
----Instructions-----
}
I feel that Synchronized block is better than making the whole method
我觉得同步块比制作整个方法更好
Synchronized
同步
回答by Mahesh Balasubramanian
As is clear from above explanations, by implementing the SingleThreadModel, a servlet can be assured thread-safety by the servlet container. The container implementation can do this in 2 ways:
从上面的解释中可以清楚地看出,通过实现SingleThreadModel,servlet 容器可以确保 servlet 线程安全。容器实现可以通过两种方式做到这一点:
1) Serializing requests (queuing) to a single instance - this is similar to a servlet NOT implementing SingleThreadModel BUT synchronizing the service/ doXXX methods; OR
1) 将请求序列化(排队)到单个实例——这类似于一个不实现 SingleThreadModel 但同步服务/ doXXX 方法的 servlet;或者
2) Creating a pool of instances - which's a better option and a trade-off between the boot-up/initialization effort/time of the servlet as against the restrictive parameters (memory/ CPU time) of the environment hosting the servlet.
2) 创建实例池 - 这是一个更好的选择,也是 servlet 的启动/初始化工作/时间与托管 servlet 的环境的限制性参数(内存/CPU 时间)之间的权衡。