Servlet的多线程机制
Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例。Servlet容器会自动使用线程池等技术来当两个或多个线程同时访问同一个Servlet时,可能会发生多个线程同时访问同一资源的情况,数据可能会变得不一致。所以在用Servlet构建的Web应用时如果不注意线程安全的问题,会使所写的Servlet程序有难以发现的错误支持系统的运行。
设计线程安全的
1、实现 SingleThreadModel 接口
该接口指定了系统如何处理对同一个Servlet的调用。如果一个Servlet被这个接口指定,那么在这个Servlet中的service方法将不会有两个线程被同时执行,当然也就不存在线程安全的问题。这种方法只要将前面的Concurrent Test类的类头定义更改为:
public class ConcurrentTest extends HttpServlet implements SingleThreadModel {
2、同步对共享数据的操作
使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段。通过同步块操作来保证线程的安全。
1 public class ConcurrentTest extends HttpServlet { 2 PrintWriter out; 3 @Override 4 protected void service(HttpServletRequest request, HttpServletResponse response) 5 throws ServletException, IOException { 6 String username; 7 response.setContentType("text/html;charset=gb2312"); 8 username=request.getParameter("username"); 9 synchronized(this){ 10 output=response.getWriter(); 11 try { 12 //为了突出并发问题,在这设置一个延时 13 Thread.sleep(5000); 14 out.println("用户名:"+username+"<BR>"); 15 } catch (Exception e) { 16 e.printStackTrace(); 17 } 18 } 19 } 20 }
3、避免使用实例变量
只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的。
1 public class ConcurrentTest extends HttpServlet { 2 @Override 3 protected void service(HttpServletRequest request, HttpServletResponse response) 4 throws ServletException, IOException { 5 PrintWriter output; 6 String username; 7 response.setContentType("text/html;charset=gb2312"); 8 username=request.getParameter("username"); 9 synchronized(this){ 10 output=response.getWriter(); 11 try { 12 //为了突出并发问题,在这设置一个延时 13 Thread.sleep(5000); 14 output.println("用户名:"+username+"<BR>"); 15 } catch (Exception e) { 16 e.printStackTrace(); 17 } 18 } 19 } 20 }