多用户访问servlet时,Servlet中出现的由多线程引起的问题


public class MyClass {
    private String variable1 ;
    private static String variable2 ;
    public MyClass(){   
    }
    public void method(){
        String variable3;
    }
 }
上面是随手写的一个类,没有任何意义,只是为了强调一些概念,这和这个主题很有关系:
1) java中的变量的分类:
    a. 实例变量
    b. 局部变量
    c. 静态变量
本篇并不是java的基础教程,因此不会详尽到每个基础知识点(下面的内容是区分对象和对象变量这两个概念的,<<core java2>>严格区分,不过大多数教材并不过于苛刻的区别它们)
a. 实例变量:属于每个对象,也就是每个对象都有一份此变量的副本。上面的variable1就指向实例变量。
b. 局部变量:工作在某个作用域,离开作用域之后成为垃圾。上面的variable3就指向局部变量,局部变量存在于方法中。
c. 静态变量:属于某个类,也就是所有对象共有一个副本。上面的variable2就指向静态变量。

2) servlet容器的实例化:
servlet如何被实例化的,不是我们所关心的,我们关心的是servlet被实例化了多少次,是每一次请求都实例化还是仅仅实例化一次?要解答这个问题太简单了:


public class Test extends HttpServlet {
    private static int count = 0;
    private int num = 0;
   
    public Test() {
        super();
        count ++;
        System.out.println("实例化了 "+count+" 次");
    }
 
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html");
        num ++;
        System.out.println("被访问了" + num+"次");
    }
}


打开浏览器,访问指定的servlet,不断点刷新,结果是:
实例化了 1 次
被访问了1次
被访问了2次
被访问了3次

不要关闭浏览器,再开一个浏览器访问,不断点刷新,结果是:
被访问了4次
被访问了5次
被访问了6次
被访问了7次
被访问了8次

可见对不仅仅是对同一个用户,对于其他用户也只实例化一个对象。
也就是说,Tomcat仅仅实例化一次servlet,产生一个对象。

那servlet容器是如何相应多用户同时访问的呢?回答:多线程。为每次访问都用一个独立的线程运行doGet或者是doPost方法。也就是servlet容器的内部实现可能是这样的:

class . extends Thread{
    public void run(){
       if(request 为 get)
           servlet.doGet();   // servlet指向你请求的servlet类的实例
       else if(request 为 post)
           servlet.doPost();
    }
}


这没什么问题,但是一些初级程序员可能放这样的错误:
public class Test extends HttpServlet {
    private PrintWriter out ;
 
    public Test() {
        super();
    }
 
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html");
       out = response.getWriter();
       out.println(request.getRemoteAddr());
    }
}


会有什么结果?单A访问这个Test,通过response.getWriter()得到一个实例,保存在out中,假定这时候B在A之前执行完了response.getWriter(),并开始执行out.println(request.getRemoteAddr()),这时候out保存的并不是B自己通过getWriter()方法得到的PrintWriter对象,而是A运行getWriter的结果,那么B就输出了A的地址。再看看下面的例子:

建立一个webapp,名字叫做web,建立sendname.html的HTML文件,内容如下:


<html>
  <head></head>
  <body>
        <form action="/web/Test">
            <input type="text" name="name"/>
            <input type="submit" />
        </form>
  </body>
</html>

在<%! %>中定义的方式也会被多线程调用。
对于JSP页面,除了使用synchronized,还可以使用page指令元素的isThreadSafe来控制整个页面是否可以多线程访问。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值