现在的位置: 首页 > 综合 > 正文

Servlet 线程安全问题

2014年01月08日 ⁄ 综合 ⁄ 共 1195字 ⁄ 字号 评论关闭

之前写过一篇关于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的内存模型JMMJava Memory ModelJMM主要是为了规定了线程和内存之间的一些关系。根据JMM的设计,系统存在一个主内存(Main Memory)Java中所有实例变量都储存在主存中,对于所有线程都是共享的。每条线程都有自己的工作内存(Working Memory),工作内存由缓存和堆栈两部分组成,缓存中保存的是主存中变量的拷贝,缓存可能并不总和主存同步,也就是缓存中变量的修改可能没有立刻写到主存中;堆栈中保存的是线程的局部变量,线程之间无法相互直接访问堆栈中的变量。根据JMM,我们可以将论文中所讨论的Servlet实例的内存模型抽象为


由于b线程对实例变量output的修改覆盖了a线程对实例变量output的修改,从而导致了用户a的信息显示在了用户b的浏览器上。如果在a线程执行输出语句时,b线程对output的修改还没有刷新到主存,那么将不会出现线程的问题。

解决方法有3种:

第一种:实现 SingleThreadModel 接口(不能解决并发量的问题,不可取)

第二种:同步对共享数据的操作(synchronized)

第三种:避免使用全局变量

再此推荐大家使用第三种。

下面是Servlet常用类得线程安全情况:

ServletContext:(线程是不安全的);HttpSession:(线程是不安全的); ServletRequest:(线程是安全的);

    其实稍微有经验的程序员都可以猜到。

抱歉!评论已关闭.