• Servlet--理解


    1.servlet运行在服务器上应用程序,它担当一个HTTP客户程序与服务器上数据库之间联系的中间层。擅长处理 流程和业务逻辑。

    一.工作原理:服务器只创建每一个Servlet的单一的实例,对于并发请求会有线程安全问题

    首次创建servlet时初次调用init()方法,servlet接受到用户的请求时候,为每一个用户分配一个线程,多个并发的请求导致线程同时调用service方法,service方法根据请求类型调用doGET,doPost方法,最后服务器想卸载某个servlet时候首先调用servlet的destroy的方法

    二.servlet 的生命周期: servlet被装载--->实例化---->服务---->销毁。

    1.Servlet装载,servlet容器加载servlet 调用init()方法进行初始化操作,整个生命周期中,init()方法只能被调用一次

    2.service()方法,是servlet的核心servlet接受到用户的请求时候,为每一个用户分配一个线程,多个并发的请求导致线程同时调用service方法,service方法根据请求类型调用doGET,doPost方法

    3.destroy() 方法:只执行一次,服务器准备卸载servlet时候才会电调用此方法。

    servlet深入理解:

    根接口:

     Servlet接口

        |---GenericServlet:不依附特定协议

            |----HttpServlet(主要的实现类):基于HttpServlet:将ServletRequest强制转成HttpRequest

          servlet运行在任何的服务器上,每一个Servlet直接或者间接实现了servlet的接口 ,servlet接口定义五的方法,其中的三个方法 init(),service(),destory()的方法关于生命周期的;

    为了servlet设计方便,GenericServlet类实现servlet的接口,不依附任何协议的servlet。而HttpServlet继承GenericServlet类同样实现servlet接口,因此在实际过程 写servlet只需要继承HttpServlet就行

            Servlet接口和GenericServlet是不特定于任何协议的,而HttpServlet是特定于HTTP协议的类,所以HttpServlet中实现了service()方法,并将请求ServletRequest,ServletResponse强转为HttpRequest和HttpResponse。

    三.多个用户同时调用同一个servlet,由于服务器只创建servlet的单一实例,多个请求产生多个线程调用同一个servlet时候出现线程安全问题:

        解决方法:  1.多线程不共享局部变量,尽可能用局部变量

                          2.成员共享变量 加上sychronized进行锁限制

                          3.使用单例模式,对方法进行sychronized,将并发请求转换成串性; 

                 1.不能真正共享数据,使用非静态变量存储数据,导致同一个servlet类多个请求申请多个单例对象

                  2.使用静态变量存储数据,每一个请求实例化一个单例同样并发访问静态变量,解决共享静态数据问题又引入线程不安全,最好使用sychronized块对共享变量进行上锁

    从上理解得出 Servlet服务器开辟多个线程,来处理请求,多个线程访问同一个servlet对象,对于共享的数据不得不 加上sychronized进行同步,或者将全局,静态变量写出局部变量,多线程不共享局部变量

     1)servlet容器为了响应多个用户同时访问一个servlet的HTTP请求时候,servlet容器为每一个请求分配一个工作线程,这些线程同时并发执行servlet的service的方法,发生多线程同时访问同一数据的情况

     1 public class Hello extends HttpServlet{
     2     private String name;
     3     
     4     public void doPost(HttpServletRequest request,HttpServletResponse response)
     5         throws ServletException,java.io.IOException{
     6         
     7         response.setContentType("text/html;charset=UTF-8");
     8         
     9         name = (String)request.getParameter("name");    //接收参数
    10         
    11         PrintWriter out = response.getWriter();
    12         out.println("<html><head><title>test</title></head><body>");
    13         out.println("你好"+name);
    14         out.println("</body></html>");
    15                 
    16         out.close();
    17     }
    18 }

    如果多线程并发访问,会访问同一个实例变量,则会共用name,而出现用户得到数据不一致的现象

    解决的方式:

    1.使用局部变量的方式:

     1     
     2 public class Hello extends HttpServlet{
     3     
     4     public void doPost(HttpServletRequest request,HttpServletResponse response)
     5         throws ServletException,java.io.IOException{
     6         
     7         response.setContentType("text/html;charset=UTF-8");
     8         
     9         String name = (String)request.getParameter("name");    //接收参数
    10         
    11         ...
    12     }
    13 }

    每当一个线程执行doPost()时,在线程的堆栈中就会创建name这个局部变量,当线程执行完该方法,局部变量就结束生命周期。如果多个线程同时执行该方法,那么每个线程都拥有自己的局部变量

    2.java 中使用同步机制:计算共享变量

     1 public class Hello extends HttpServlet{
     2     private String name;
     3     
     4     public void doPost(HttpServletRequest request,HttpServletResponse response)
     5         throws ServletException,java.io.IOException{
     6         
     7         response.setContentType("text/html;charset=UTF-8");
     8         
     9         synchronized(this){
    10             name = (String)request.getParameter("name");    //接收参数
    11             ...
    12         }
    13         ...
    14     }
    15 }

    3.实现被废弃的SingleThreadModel接口 :

      对于实现此接口则Servlet容器实现可以采用以下两种方式之一来运行Servlet: 
    1)在任意一时刻,只允许有一个工作线程执行Servlet的service()方法。如果有多个用户同时请求访问该Servlet,那么这些客户请求被放入等待队列,容器会依次响应等待队列中的每个客户请求。这种实现方式实际上禁止了多个客户端对同一个Servlet的并发访问。 
    2)Servlet容器为每个Servlet创建一个对象池,在这个池中存放了同一个Servlet类的多个实例。如果有多个用户同时请求访问该Servlet,Servlet容器会为每个请求分配一个工作线程,并且从对象池中取出一个空闲的Servlet实例,把它分配给工作线程。每个工作线程执行自己的Servlet实例的service()方法。这种实现方式表面上允许客户端对同一个Servlet并发访问,但实际上不同客户端访问的是同一个Servlet类的不同实例。 
    如果实例变量需要共享,用以进行计算,这种方法并不能有效的避免并发问题。

  • 相关阅读:
    nginx超时问题
    linux打包文件,压缩文件
    centos查看文件夹大小
    Nginx反向代理和负载均衡
    nginx的location配置详解
    nginx错误Upstream timed out
    mysql处理函数
    SQL左右连接中的on and和on where的区别
    html select change事件触发
    get,post区别
  • 原文地址:https://www.cnblogs.com/woainifanfan/p/6725205.html
Copyright © 2020-2023  润新知