Servlet是线程安全的吗?被面试官问到崩溃
Servlet不是线程安全的。
要解释为什么Servlet为什么不是线程安全的,需要了解Servlet容器(即Tomcat)使如何响应HTTP请求的。
当Tomcat接收到Client的HTTP请求时,Tomcat从线程池中取出一个线程,之后找到该请求对应的Servlet对象并进行初始化,之后调用service()方法。要注意的是每一个Servlet对象再Tomcat容器中只有一个实例对象,即是单例模式。如果多个HTTP请求请求的是同一个Servlet,那么着两个HTTP请求对应的线程将并发调用Servlet的service()方法。
上图中的Thread1和Thread2调用了同一个Servlet1,所以此时如果Servlet1中定义了实例变量或静态变量,那么可能会发生线程安全问题(因为所有的线程都可能使用这些变量)。
比如下面的Servlet中的 name 和 i变量就会引发线程安全问题。
importjavax.servlet.ServletException;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.text.SimpleDateFormat;importjava.util.Date;publicclassThreadSafeServletextendsHttpServlet{publicstaticString name ="Hello";//静态变量,可能发生线程安全问题int i;//实例变量,可能发生线程安全问题SimpleDateFormat format =newSimpleDateFormat("yyyy-MM-dd hh:mm:ss"); @Overridepublicvoidinit() throws ServletException {super.init(); System.out.println("Servlet初始化"); } @Overrideprotectedvoidservice(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.printf("%s:%s[%s]\n", Thread.currentThread().getName(), i, format.format(newDate())); i++;try{ Thread.sleep(5000); }catch(InterruptedException e) { e.printStackTrace(); } System.out.printf("%s:%s[%s]\n", Thread.currentThread().getName(), i, format.format(newDate())); resp.getWriter().println("<html><body><h1>"+ i +"</h1></body></html>"); }}
在Tomcat中启动这个Servlet并在浏览器发起多个HTTP访问,最后会发现变量 i 是多线程共享的。
感谢你看完文章,小编最近收藏了一大波各大BAT面试真题资料,免费送给正在找工作的你或者想换工作的你,加q:2735398787 欢迎自取