Servlet和Action的线程安全问题

Servlet不是线程安全的,同样Action继承与Servlet,Action也不是线程安全的。

具体先从Servlet讲起:

JSP和Servlet默认是在JAVA多线程机制上多线程执行的,这是JSP的优势之一。也就是说,当web用户第一次访问某个Servlet时,容器根据web.xml实例化该servlet,之后的其他访问都会使用同一个servlet,这样就出现了多个用户同时访问时,可能会出现多个线程同时访问某一资源的情况,数据就可能会变得不一致。而这种线程安全问题主要由实例变量使用不当引起的。

public class ConcurrentServlet extends HttpServlet{

    PrintWriter output;    //实例变量

    String username;

    public void service(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException{

        output=response.getWriter();     //潜在资源访问冲突

        username=request.getParameter("username");

        output.println("username:"+username);

    }

}

当同时访问

    http://localhost:8080/.../ConcurrentServlet?username=a

    http://localhost:8080/.../ConcurrentServlet?username=b

时就产生了对实例变量output的争用,可能出现的结果:

    其中一个用户得到了空白的页面,另一个用户同时得到了全部的输出,如图所示:

    解决的办法:

    一、设置为单线程

       Servlet 实现SingleThreadModel接口,Action可以在配置文件中奖Singleton属性设置为true

       Servlet:

             public class ConcurrentServlet extends HttpServlet implements SingleThreadModel{...}

       Action:   

             <bean ... singleton="true">

                       <property>...</property>

                        ...

              </bean>

       设置为单线程,当然就不会产生多线程资源争用的问题,但是这样就使应用的性能大大降低,除非绝对必要,否则,不要这么做

    二、不使用实例变量

       public class ConcurrentServlet extends HttpServlet{

              public void service(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException{

              PrintWriter output=response.getWriter();     //将类实例变量改为类函数的局部变量,每个线程都要建立自己的变量

              String username=request.getParameter("username");//参考线程的工作原理

              output.println("username:"+username);

              }

       }

       Action与Servlet遵循相同的原则

    三、将不得不适用实例变量的部分,syn化

     

      public class ConcurrentServlet extends HttpServlet{

             PrintWriter output;    //实例变量

             String username;

             public void service(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException{

             Synchronized(this){

                  output=response.getWriter();     //潜在资源访问冲突

                  username=request.getParameter("username");

                  output.println("username:"+username);

             }

             }

     }

      Action遵循相同的原则

 

这样的线程安全只有在大规模并发访问的时候才可能发生,所以在开发时往往不容易发现。而问题的根源在于实例变量,所以写程序的时候要遵循以下原则:

    ①避免使用实例变量

    ②不得不使用实例变量的地方同步化

    ③从效率上考虑,尽量减少同步的代码量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值