我们都知道servlet是线程不安全的,但是到底是怎么不安全的,我们今天来看一下
首先,我们先建立一个jsp去进行一下测试,看看servlet对于变量的测试
<%@
page
language
=
"java"
import
=
"java.util.*"
pageEncoding
=
"UTF-8"
%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+
"://"
+request.getServerName()+
":"
+request.getServerPort()+path+
"/"
;
%>
<!
DOCTYPE
HTML
PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN">
<
html
>
<
head
>
<
title
>
Servlet测试
</
title
>
</
head
>
<
body
>
<
a
href
=
"
<%=
path
%>
/servlet/ServletTest"
>
Servlet测试
</
a
>
</
body
>
</
html
>
内部仅有一个a标签,下面写一个servlet
import
java.io.IOException;
import
java.io.PrintWriter;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
ServletTest
extends
HttpServlet {
int
count
=0;
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, 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的,那么只有可能是同一个对象,下面我们来写一段代码去验证一下:
首先建立一个学生类:
public
class
Student {
public
int
age
;
public
void
add(){
this
.
age
++;
System.
out
.println(
"年龄是:"
+
this
.
age
);
}
}
在建立一个测试类:
public
class
TestMain {
public
static
void
main(String[] args) {
Student stu=
new
Student();
stu.add();
stu.add();
stu.add();
}
}
创建一个学生的对象多次调用的时候就会在控制台打印:
当我们在创建一个对象的时候,那数据就会被覆盖,重新开始计数:
public
class
TestMain {
public
static
void
main(String[] args) {
Student stu=
new
Student();
stu.add();
stu.add();
stu.add();
System.
out
.println(
"===================="
);
Student stu1=
new
Student();
stu1.add();
stu1.add();
stu1.add();
}
}
控制台结果:
所以我现在就把上面的servlet代码更改一下,我们把count从外面接收一下:
import
java.io.IOException;
import
java.io.PrintWriter;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
ServletTest
extends
HttpServlet {
int
count
=0;
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, 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的线程不安全
所以我们只要把代码放到synchronized,代码如下:
import
java.io.IOException;
import
java.io.PrintWriter;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
ServletTest
extends
HttpServlet {
int
count
=0;
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, 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
++);
}
}
}
希望有什么不好的多多交流。。。。。
转载于:https://blog.51cto.com/7915791/1401978