多用户访问servlet时,Servlet中出现的由多线程引起的问题。
来源:互联网 发布:kettle7.1源码搭建 编辑:程序博客网 时间:2024/05/22 09:01
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>
建立一个servlet叫Test,内容如下:
public class Test extends HttpServlet { private String name ; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); name = request.getParameter("name"); out.println("I input "+name); try{Thread.sleep(5000);}catch(Exception ex){} out.println("I am "+name); out.flush(); out.close(); }}
通过浏览器打开2个sendname.html(http://localhost:8080/web/sendname.html),分别输入名字A和B(间隔不要超过5秒):
结果2个页面显示分别是:
I input B I am B
I input A I am B
这就是Servlet中的多线程问题。解决的办法很简单,就是不用实例变量,至少不在绝对必要的时候用。
在JSP中这样的问题更加突出,因为使用<%! %>进行的变量声明得到的是一个实例变量,如果一定要定义,那么就使用synchronized,在使用实例变量的方法前加上synchronized,它也是不推荐使用的,下面是一个例子:
<%@ page contentType="text/html;charset=GB2312" %><HTML><BODY> <!--number 为临界区--> <%! int number=0; synchronized void countPeople() { number++; } %> <% countPeople(); %><P><P>您是第 <%=number%>个访问本站的客户。</BODY></HTML>
在<%! %>中定义的方式也会被多线程调用。
对于JSP页面,除了使用synchronized,还可以使用page指令元素的isThreadSafe来控制整个页面是否可以多线程访问。
- 多用户访问servlet时,Servlet中出现的由多线程引起的问题。
- Servlet中出现的由多线程引起的问题
- Servlet中出现的由多线程引起的问题
- servlet多线程的问题
- Servlet的多线程问题
- Servlet的多线程问题
- servlet多线程的问题
- Servlet的多线程问题
- servlet出现的问题
- Servlet基础 ----- Servlet的多线程同步问题
- Servlet 的路径访问问题
- servlet 多线程问题的研究
- Servlet 多线程问题的研究
- Servlet的多线程同步问题
- Servlet的多线程并发问题
- Servlet的多线程并发问题
- Servlet的多线程同步问题
- Java Servlet 中Servlet地址的问题
- Webkit For Android
- 此生,依旧是我未看破红尘。
- ffmpeg在win32中的编译
- def文件一个比较详细的例子
- [Android] Android应用插件式开发解决方法
- 多用户访问servlet时,Servlet中出现的由多线程引起的问题。
- strcpy和memcpy的区别
- oracle 11g 手动配置EM
- USB设备的枚举过程
- How to pause action of cocos2d
- DataTable 添加列、设置主键、添加行、查询、更新
- 关于Activity启动模式的理解
- 北大青鸟给了你什么?
- Android五大布局