servlet生命周期和线程安全
要想写一个servlet,可以继承GenericServlet或者可以继承HttpServlet,或者可以实现servlet接口,但是现在我们大多数网站都是http协议,而且httpservlet是继承自GenericServlet有很多重写的方法,所以现在我们只需要继承httpservlet就可以。
servlet的生命周期分为三个阶段:
1.初始化阶段,调用init()方法
2.响应客户端请求,调用service()方法
3.终止阶段,调用destroy()方法
上面是一个servlet整个生命周期,整个的周期都不是我们程序员来调用或者说管理的,那么不是我们来调用的,是由谁来管理调用的?这里的是由web服务器来做的事情,当客户端请求一个servlet,这时服务器会为这个客户端初始化一个servlet,注意,这里是第一次访问,如果是第二次访问那么服务器会直接调用,不会在创建,那么服务器收到这个请求,根据资源地址对应到响应的servlet,这时服务器会调用当前servlet的service方法,来处理这个请求,处理完成后,响应给客户端。
当一个servlet被创建,这个servlet会在服务器停止的时候被销毁。
*************************************************
servlet的线程安全:
所谓的线程安全,就是多个线程同时或者共同访问同一个资源,这是会有线程安全的问题。
代码实例:
1 public class ServletDemo1 extends HttpServlet { 2 int i = 0; 3 @Override 4 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 5 throws ServletException, IOException { 6 i++; 7 try { 8 Thread.sleep(1000*4); 9 } catch (InterruptedException e) { 10 e.printStackTrace(); 11 } 12 resp.getOutputStream().write((i+"").getBytes()); 13 } 14 @Override 15 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 16 throws ServletException, IOException { 17 doGet(req, resp); 18 } 19 }
上面这样写的话,给一个场景,有两个用户来访问,第一个用户开始访问,第二个紧接着访问,正常来说第一个用户应该得到的是1,但是这里却得到的是2,这里就是一个进程安全,那么这个怎么解决呢,有一个同步代码块,我们就把可能会出现线程安全的代码放在这个同步代码块里面,就可以避免这样的问题,
1 int i = 0; 2 @Override 3 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 4 throws ServletException, IOException { 5 synchronized (this) { 6 i++; 7 try { 8 Thread.sleep(1000*4); 9 } catch (InterruptedException e) { 10 e.printStackTrace(); 11 } 12 resp.getOutputStream().write((i+"").getBytes()); 13 } 14 15 }
这样就能解决线程安全问题,但是这个synchronized同步代码块执行的原理是,第一个用户请求完成了,我才去解决第二个请求,这个能把人逼疯啊,
还有一个方法能决绝但是,这个过时了,不提倡试用,就是你这个servlet实现标记接口SingleThreadModel类,这个类里面什么都没有,空接口,这样的接口我们称之为标记接口。
1 public class ServletDemo1 extends HttpServlet implements SingleThreadModel{ 2 int i = 0; 3 @Override 4 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 5 throws ServletException, IOException { 6 i++; 7 try { 8 Thread.sleep(1000*4); 9 } catch (InterruptedException e) { 10 e.printStackTrace(); 11 } 12 resp.getOutputStream().write((i+"").getBytes()); 13 } 14 @Override 15 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 16 throws ServletException, IOException { 17 doGet(req, resp); 18 } 19 }