实现SingleThreadModel,容器不为servlet创建新的实例的问题

在百度贴吧看到这样一个问题,于是自己给了答复,感觉这个问题还是蛮有意思的,所有记录下来。贴吧地址:

http://zhidao.baidu.com/question/209371363.html
问题:

听说实现SingleThreadModel,可以使容器对客户端的每个请求创建新的servlet实例,但是我实现了那个接口之后,还是不行阿。
比如,我给servlet增加属性int count = 0;在doGet()方法里System.out.println(count++);为什么不是每次访问都输出0,而是递增呢?
回答:

其实是有实例的,当一个servlet实现了SingleThreadModel接口之后就会有一个Stack来保存这些实例。 至于为什么每次访问都是递增的。是因为当请求的实例数大于当前实例数的时候才会重新去加载个实例,然后放到Stack中,很明显,楼主第一次请求完后该实例被回收到Stack中,第二次请求时发现Stack中有实例供调用,当然就用Stack中的实例了而不会去重新加载了。

可以查看org.apache.catalina.core.StandardWrapper类的allocate方法。

 

 public Servlet allocate() throws ServletException {

        if (debug >= 1)
            log("Allocating an instance");

        // If we are currently unloading this servlet, throw an exception
        if (unloading)
            throw new ServletException
              (sm.getString("standardWrapper.unloading", getName()));

        // If not SingleThreadedModel, return the same instance every time
        if (!singleThreadModel) {

            // Load and initialize our instance if necessary
            if (instance == null) {
                synchronized (this) {
                    if (instance == null) {
                        try {
                            instance = loadServlet();
                        } catch (ServletException e) {
                            throw e;
                        } catch (Throwable e) {
                            throw new ServletException
                                (sm.getString("standardWrapper.allocate"), e);
                        }
                    }
                }
            }

            if (!singleThreadModel) {
                if (debug >= 2)
                    log("  Returning non-STM instance");
                countAllocated++;
                return (instance);
            }

        }

        synchronized (instancePool) {

            while (countAllocated >= nInstances) {//请求的数量大于当前的实例数才会加载新的实例的
                // Allocate a new instance if possible, or else wait
                if (nInstances < maxInstances) {
                    try {
                        instancePool.push(loadServlet());//在这加载
                        nInstances++;
                    } catch (ServletException e) {
                        throw e;
                    } catch (Throwable e) {
                        throw new ServletException
                            (sm.getString("standardWrapper.allocate"), e);
                    }
                } else {
                    try {
                        instancePool.wait();
                    } catch (InterruptedException e) {
                        ;
                    }
                }
            }
            if (debug >= 2)
                log("  Returning allocated STM instance");
            countAllocated++;
            return (Servlet) instancePool.pop();

        }

    }
当一个实例调用完之后会被回收到Stack中

 

  public void deallocate(Servlet servlet) throws ServletException {

        // If not SingleThreadModel, no action is required
        if (!singleThreadModel) {
            countAllocated--;
            return;
        }

        // Unlock and free this instance
        synchronized (instancePool) {
            countAllocated--;
            instancePool.push(servlet);
            instancePool.notify();
        }

    }

从以上的代码可以看出,SingleThreadModel接口使Servlet程序员产生虚假的安全感,认为它是线程安全的。实际上该接口并不能避免同步而产生的问题,如访问静态类变量或该servlet以外的类或变量,即使访问该servlet类自身的属性也得很小心(如那个问题所描述的问题)。所以Servlet 2.4中已经废弃了该接口,不建议写servlet的时候继承该接口。因而对于大多数的servlet来说都是单例的。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值