@867976167
2014-10-11T14:39:57.000000Z
字数 1716
阅读 1969
Servlet,多线程
首先说明Servlet并非线程安全,在所有对某个url的请求全部被转发到同一个Servlet。所以在开发Servlet过程尽量不使用实例变量,而使用局部变量。虽然在整个应用过程中只有一个Servlet,但是Servlet并不是单例模式,Server只是被容器创建一次,所以才只存在一个Servlet实例。
下面简单介绍Servlet请求过程主要参考stackoverflow的一个回答:
当容器启动时候:
1.读取web.xml文件,根据Servlet的 load-on-startup属性确定是否启动,非负时候Servlet会被启动。
2.获得Servlet的路径
3.加载并且实例化Servlet,只实例化一次
就如下面:
String urlPattern = parseWebXmlAndRetrieveServletUrlPattern();
String servletClass = parseWebXmlAndRetrieveServletClass();
HttpServlet servlet = (HttpServlet) Class.forName(servletClass).newInstance();
servlet.init();
servlets.put(urlPattern, servlet); // Similar to a map interface.
Those Servlets are stored in memory and reused every time the request URL matches the Servlet's associated url-pattern. The servlet container then executes code similar to:
这些Servlet被加载到内存,每次请求都会使用相同的servlet。容器将会执行如下代码:
for (Entry<String, HttpServlet> entry : servlets.entrySet()) {
String urlPattern = entry.getKey();
HttpServlet servlet = entry.getValue();
if (request.getRequestURL().matches(urlPattern)) {
servlet.service(request, response);
break;
}
}
service根据请求类型(post,get)转发到相应方法doGet,doPost;
Servlet容器对于相同的请求使用的是同一Servlet,即Servlet被共享给每个request。所以应该注意:
1.不用实例变量。
2.不要在Servlet的方法加 synchronized关键字.
public class MyServlet extends HttpServlet {
private Object thisIsNOTThreadSafe;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object thisIsThreadSafe;
thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!!所有请求共享
thisIsThreadSafe = request.getParameter("foo"); // OK, 线程安全
}
}
通过实现SingleThreadModel接口,可以每次请求都创建一个新的Servlet,但由于静态变量和session,依然存在线程安全性问题。所以此接口不推荐使用。
session不是线程安全的,当同一用户在不同浏览器请求时候可能导致线程问题。
1.Struts1不是线程安全的;Struts1的Action是单例模式,每次请求使用一个Action。Struts1太老,认为创建新的实例花费太大,所以使用单例模式。
2.Struts2是线程安全的;每次请求创建新的Action,线程安全。