zoukankan      html  css  js  c++  java
  • servlet是单例还是多例

    单实例多线程

    Servlet容器默认是采用单实例多线程的方式处理多个请求的:
    1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在一个Servlet实例);
    2.容器初始化化Servlet主要就是读取配置文件(例如tomcat,可以通过servlet.xml的<Connector>设置线程池中线程数目,初始化线程池通过web.xml,初始化每个参数值等等。
    3.当请求到达时,Servlet容器通过调度线程(Dispatchaer Thread) 调度它管理下线程池中等待执行的线程(Worker Thread)给请求者;
    4.线程执行Servlet的service方法;
    5.请求结束,放回线程池,等待被调用;
    (注意:避免使用实例变量(成员变量),因为如果存在成员变量,可能发生多线程同时访问该资源时,都来操作它,照成数据的不一致,因此产生线程安全问题)

    单实例有状态

    不是单例,只能说web容器对servlet实例化了一次。servlet只是一个普通的类,它也有自已的构造函数,甚至可以用new的方式new出N多个servlet的实例,但它能正常地处理web请求,就需要交给web服务器(或者叫servlet/jsp容器)来进行管理,比如说tomcat,tomcat通过配置文件获取映射信息,然后只会在第一次生成servlet的实例,并把它缓存起来,下次再次请求,同样是取的这个实例,所以它的之前状态还是被保存起来的,所以共享的数据如果不是线程安全的,会出问题,所以别把数据用成员属性进行保存,别让servlet有状态。

    源码分析

    在Servlet规范中,对于Servlet单例与多例定义如下:

    “Deployment Descriptor”, controls how the servlet container provides instances of the servlet.For a servlet not hosted in a distributed environment (the default), the servlet container must use only one instance per servlet declaration. However, for a servlet implementing the SingleThreadModel interface, the servlet container may instantiate multiple instances to handle a heavy request load and serialize requests to a particular instance.

    上面规范提到,
    如果一个Servlet没有被部署在分布式的环境中,一般web.xml中声明的一个Servlet只对应一个实例。

    而如果一个Servlet实现了SingleThreadModel接口,就会被初始化多个实例。实例有多少呢,这里没细说。

    下面再从Tomcat的源码中找寻下具体的参考实现是什么样子的。以下代码来源于Tomcat的StandardWrapper类。

    public Servlet allocate() throws ServletException {
    boolean newInstance = false;
    if (!singleThreadModel) {
    // Load and initialize our instance if necessary
    if (instance == null) {
    synchronized (this) {
    if (instance == null) {
    try {
    instance = loadServlet();
    } catch (ServletException e) {}}}}
    if (singleThreadModel) {
    if (newInstance) {
    synchronized (instancePool) {
    instancePool.push(instance); //如果实现STM接口,就放到一个栈里
    nInstances++;
    }}
    } else {
    if (!newInstance) {
    countAllocated.incrementAndGet();
    }
    return (instance);
    }
    }
    synchronized (instancePool) {
    while (countAllocated.get() >= nInstances) {
    // Allocate a new instance if possible, or else wait
    if (nInstances < maxInstances) {
    try {
    instancePool.push(loadServlet());
    nInstances++;
    } catch (ServletException e) {}
    } else {
    try {
    instancePool.wait();
    } catch (InterruptedException e) {
    // Ignore
    }} }
    countAllocated.incrementAndGet();
    return instancePool.pop();
    }}
    /**
    * Load and initialize an instance of this servlet, if there is not already
    * at least one initialized instance. This can be used, for example, to
    * load servlets that are marked in the deployment descriptor to be loaded
    * at server startup time.
    */
    public synchronized Servlet loadServlet() throws ServletException {
    // Nothing to do if we already have an instance or an instance pool
    if (!singleThreadModel && (instance != null))
    return instance; //注意此处,如果存在实例就直接返回
    Servlet servlet;
    try {
    InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager();
    try {
    servlet = (Servlet) instanceManager.newInstance(servletClass);
    } catch (ClassCastException e) {
    }
    if (servlet instanceof SingleThreadModel) {
    if (instancePool == null) {
    instancePool = new Stack<>();
    } //此处,使用Stack存放STM的Servlet
    singleThreadModel = true;
    }
    initServlet(servlet);
    } finally {
    }
    return servlet;
    }

    那一个实现了SingleThreadModel接口的Servlet,一般会初始化多少个实例呢?
    StandardWrapper类中有两个属性,其中maxInstance初始为20。所以上面的问题就有了答案。

    /**
     * Does this servlet implement the SingleThreadModel interface?
     */
    protected volatile boolean singleThreadModel = false;
    /**
     * Maximum number of STM instances.
     */
    protected int maxInstances = 20;

    由于SingleThreadModel已经声明为废弃,官方不建议使用。

    总结下,一个Servlet究竟有几个实例呢?受如下几个原因影响:
    是否在分布式环境中部署
    是否实现SingleThreadModel,如果实现则最多会创建20个实例
    在web.xml中声明了几次,即使同一个Servlet,如果声明多次,也会生成多个实例。

  • 相关阅读:
    1012 The Best Rank (25 分)(排序)
    1011. World Cup Betting (20)(查找元素)
    1009 Product of Polynomials (25 分)(模拟)
    1008 Elevator (20 分)(数学问题)
    1006 Sign In and Sign Out (25 分)(查找元素)
    1005 Spell It Right (20 分)(字符串处理)
    Kafka Connect 出现ERROR Failed to flush WorkerSourceTask{id=local-file-source-0}, timed out while wait
    flume、kafka、avro组成的消息系统
    Java23种设计模式总结【转载】
    Java编程 思维导图
  • 原文地址:https://www.cnblogs.com/stono/p/14234241.html
Copyright © 2011-2022 走看看