xuexue 2016-03-07
Servlet是线程安全吗?要解决这个问题,首先要知道什么是线程安全:
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
servlet是多线程的,同时一个servlet实现类只会有一个实例对象,也就是它是Singleton的,所以多个线程是可能会访问同一个servlet实例对象的。
那么servlet是线程安全的吗?
由上面的定义可知,安不安全是由全局变量或者静态变量引起的。
由此可知,servlet是否线程安全是由它的实现来决定的,如果它内部的属性或方法会被多个线程改变,它就是线程不安全的,反之,就是线程安全的。
在网上找到一个例子,如下:
public class TestServlet extends HttpServlet { private int count = 0; @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().println("<HTML><BODY>"); response.getWriter().println(this + " ==> "); response.getWriter().println(Thread.currentThread() + ": <br>"); for(int i=0;i<5;i++){ response.getWriter().println("count = " + count + "<BR>"); try { Thread.sleep(1000); count++; } catch (Exception e) { e.printStackTrace(); } } response.getWriter().println("</BODY></HTML>"); } }
当同时打开多个浏览器,输入http://localhost:8080/ServletTest/TestServlet时,他们显示的结果不同,这就说明了对于属性count来说,它是线程不安全的,
为了解决这个问题,将代码重构,如下:
public class TestServlet extends HttpServlet { private int count = 0; private String synchronizeStr = ""; @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().println("<HTML><BODY>"); response.getWriter().println(this + " ==> "); response.getWriter().println(Thread.currentThread() + ": <br>"); synchronized (synchronizeStr){ for(int i=0;i<5;i++){ response.getWriter().println("count = " + count + "<BR>"); try { Thread.sleep(1000); count++; } catch (Exception e) { e.printStackTrace(); } } } response.getWriter().println("</BODY></HTML>"); } }