Servlet的线程安全问题

来源:互联网 发布:js倒计时10秒 编辑:程序博客网 时间:2024/05/18 01:59

前言

当有多个客户端同时访问同一个Servlet资源时,Web服务器就会为每一个客户端创建一个线程,并且调用service(..)方法,如果同时访问了service(..)方法中的共享资源,就可能会引发线程安全问题。

代码模拟线程安全

    public class Demo7 extends HttpServlet {    private static final long serialVersionUID = 1L;    //外部共享资源num    int num = 0;    public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        num++;        //为了模拟多线程同时访问,调用sleep()方法让当前线程休眠一会        try {            Thread.sleep(1000*3);        } catch (InterruptedException e) {            e.printStackTrace();        }        response.getOutputStream().write(("num is :     "+num).getBytes());    }    public void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        doGet(request, response);    }}

打开浏览器,同时打开两个窗口,同时访问Demo7这个servlet,比如A对此资源进行了访问,A应该得到的结果是num=1;这时,B线程进来了,A线程休眠未结束,而此时的num已经被A修改为1,B继续修改,此时num=2,所以当A休眠结束,得到的结果变成了A得到的num=2;这就引发了线程安全问题;

解决方案一

加上synchronized关键字

        //加上synchronized关键字,锁定当前线程        synchronized(this){            try {                num++;                Thread.sleep(1000*3);            } catch (InterruptedException e) {                e.printStackTrace();            }            response.getOutputStream().write(("num is :     "+num).getBytes());        }

对线程进行锁定可以暂时解决这个问题,但是这对性能就有了影响,当A访问时,B就要在外面等着A结束才能访问;

解决方案二

    public class Demo8 extends HttpServlet implements SingleThreadModel    //此接口已经被标记为过时

实现SingeleThreadModel接口,这个接口中没有定义任何方法,就如同Cloneable 、Serializable这些接口一样,都属于一种标记接口,当实现这个接口,就会每一个线程创建一个servlet对象,所以AB同时访问时,A有一个自己的servlet对象,B有一个自己的servlet对象,线程安全就解决了,但是,这也不是最好的解决方案,因为解决线程安全最好的方式是解决一个servlet对象被多个线程同时访问;就是struts2中,每一个Action都是设置为prototype类型,就是避免了线程安全问题

0 0