之前写过一篇关于Servlet struts2线程的文章
http://blog.csdn.net/wpjava/article/details/5628841
以前不知道servlet的线程问题,今天重新看了下博客,仔细研究了下Servlet的线程问题。
Servlet的多线程机制
Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容 器负责的。当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类。这个Servlet就被加载到内存中去了,当有新的客户端请求 该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例。
我们都知道Servlet在第一次实例化的时候调用init方法,并且在Servlet的整个生命周期只调用一次,以后的每次请求都是调用service方法,我们在servlet开发中使用全局变量的话就会导致线程问题。下面例子证明了线程问题。
以下运行:
http://localhost/test_web/servlet/TestWeb?name=123
http://localhost/test_web/servlet/TestWeb?name=456
运行结果:
上面的例子中out是全局变量,所以产生了如下的运行结果,分析原因:
Java的内存模型JMM(Java Memory Model)JMM主要是为了规定了线程和内存之间的一些关系。根据JMM的设计,系统存在一个主内存(Main Memory),Java中所有实例变量都储存在主存中,对于所有线程都是共享的。每条线程都有自己的工作内存(Working Memory),工作内存由缓存和堆栈两部分组成,缓存中保存的是主存中变量的拷贝,缓存可能并不总和主存同步,也就是缓存中变量的修改可能没有立刻写到主存中;堆栈中保存的是线程的局部变量,线程之间无法相互直接访问堆栈中的变量。根据JMM,我们可以将论文中所讨论的Servlet实例的内存模型抽象为
由于b线程对实例变量output的修改覆盖了a线程对实例变量output的修改,从而导致了用户a的信息显示在了用户b的浏览器上。如果在a线程执行输出语句时,b线程对output的修改还没有刷新到主存,那么将不会出现线程的问题。
解决方法有3种:
第一种:实现 SingleThreadModel 接口(不能解决并发量的问题,不可取)
第二种:同步对共享数据的操作(synchronized)
第三种:避免使用全局变量
再此推荐大家使用第三种。
下面是Servlet常用类得线程安全情况:
ServletContext:(线程是不安全的);HttpSession:(线程是不安全的); ServletRequest:(线程是安全的);
其实稍微有经验的程序员都可以猜到。