我们都知道servlet是线程不安全的,但是到底是怎么不安全的,我们今天来看一下
首先,我们先建立一个jsp去进行一下测试,看看servlet对于变量的测试
<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Servlet测试</title>
</head>
<body>
<ahref="<%=path%>/servlet/ServletTest">Servlet测试</a>
</body>
</html>
内部仅有一个a标签,下面写一个servlet
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
publicclassServletTestextendsHttpServlet {
intcount=0;
publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)
throwsServletException, IOException {

         response.setCharacterEncoding("gb2312");
         PrintWriter out = response.getWriter();
         out.println("servlet测试:"+this.count++);
    }
}
当你访问你的工程,并点击a标签的链接的时候就进入到servlet,但是当你在servlet的页面一直刷新的时候,会发现打印的数字一直在增加,而且当你关闭浏览器的时候重新访问,还是会从你关闭的时候的数字继续累加。
我们来想一下是什么导致了这个原因:
1.可能变量是static的,只要是静态的就只会执行一次,也就只会一直用同一个
2.可能是一个application的全局变量,我们知道网页的访问量一般都是用application去记录的
3.有可能是同一个对象
那我们看一下,首先count不是static的,而且也不是application的,那么只有可能是同一个对象,下面我们来写一段代码去验证一下:
首先建立一个学生类:
publicclassStudent {

publicintage;
publicvoidadd(){
this.age++;
         System.out.println("年龄是:"+this.age);
    }
}
在建立一个测试类:
publicclassTestMain {

publicstaticvoidmain(String[] args) {
         Student stu=newStudent();
         stu.add();
         stu.add();
         stu.add();
    }
}

创建一个学生的对象多次调用的时候就会在控制台打印:

servlet线程安全问题_servlet线程安全问题

当我们在创建一个对象的时候,那数据就会被覆盖,重新开始计数:
publicclassTestMain {

publicstaticvoidmain(String[] args) {
         Student stu=newStudent();
         stu.add();
         stu.add();
         stu.add();
         System.out.println("====================");
         Student stu1=newStudent();
         stu1.add();
         stu1.add();
         stu1.add();
    }
}

控制台结果:

servlet线程安全问题_servlet线程安全问题_02

所以我现在就把上面的servlet代码更改一下,我们把count从外面接收一下:
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
publicclassServletTestextendsHttpServlet {
intcount=0;
publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)
throwsServletException, IOException {

         response.setCharacterEncoding("gb2312");
         PrintWriter out = response.getWriter();
         String cou=request.getParameter("cou");
count=Integer.parseInt(cou);
try{
             Thread.sleep(3000);
         }catch(InterruptedException e) {
             e.printStackTrace();
         }
         out.println("servlet测试:"+this.count++);
    }
}
上面的延迟时间是为了实现并发的效果。
这样当我们访问的时候,我们就可以在浏览器传参,我们知道Get访问方式可以在浏览器传参
当我们同时访问浏览器的时候cou一个传5,一个传10

那就会在两个页面得到一个相同的数据,其中一个被另一个覆盖了

servlet线程安全问题_servlet线程安全问题_03

这就是servlet的线程不安全
所以我们只要把代码放到synchronized,代码如下:
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
publicclassServletTestextendsHttpServlet {
intcount=0;
publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)
throwsServletException, IOException {

synchronized(this){
             response.setCharacterEncoding("gb2312");
             PrintWriter out = response.getWriter();
             String cou=request.getParameter("cou");
count=Integer.parseInt(cou);
try{
                  Thread.sleep(3000);
             }catch(InterruptedException e) {
                  e.printStackTrace();
             }
             out.println("servlet测试:"+this.count++);
         }
    }
}
希望有什么不好的多多交流。。。。。