IT兄弟连 JavaWeb教程 Servlet线程安全问题

时间:2023-03-09 03:13:56
IT兄弟连 JavaWeb教程 Servlet线程安全问题

在Internet中,一个Web应用可能被来自西面八方的客户并发访问(即同时访问),而且有可能这些客户并发访问的是Web应用中的同一个Servlet,Servlet容器为了保证能同时相应多个客户端要求访问的同一个Servlet的HTTP请求,通常会为每个请求分配一个工作线程,这些工作线程并发执行同一个Servlet对象的service()方法。

当多个线程并发执行同一个Servlet对象的service()方法时,可能会导致并发问题。

例:下面的案例用于演示导致并发问题的情形。

public class HelloServlet extends HttpServlet{

public void service(HttpServletRequest request,

HttpServletResponse response)throws ServletException,IOException{

private String username = null;

username = request.getParameter("username");

if(username != null){

username = new String(username.getBytes("ISO-8859-1"),"utf-8");

}

try{

Thread.sleep(3000);

}catch(Exception e){

e.printStackTrace();

}

response.setContentType("text/html;charset=utf-8");

PrintWriter out = response.getWriter();

out.println("您好:" + username);

out.close();

}

}

在HelloServlet中有一个实例变量username,在HelloServlet的service()方法中,先将username请求参数赋值给实例变量username,最后再向客户端返回实例变量username的值,为了延长响应客户请求的时间,在service()方法中调用Thread.sleep(3000)方法睡眠3秒。

在web.xml文件中为HelloServlet映射的URL为"/hello"。同时打开两个浏览器,分别输入如下URL:

http://localhost:8080/helloapp/hello?username=老鼠

http://localhost:8080/helloapp/hello?username=小鸭

以上两个浏览器并发访问HelloServlet,出现了奇怪的现象。在第一个浏览器中,虽然客户端提供的请求参数username的值为"老鼠",HelloServlet却返回"您好:小鸭"。为什么一眨眼,老鼠就变成了鸭呢?

下面在看另一个案例:

public class AdderServlet extends HttpServlet{

public void service(HttpServletRequest request,

HttpServletResponse response)throws ServletException,IOException{

private int sum = 100;

int increase = Integer.parseInt(request.getParameter("increase"));

response.setContentType("text/html;charset=UTF-8");

PrintWriter out = response.getWriter();

out.println(sum + "+" + increase + "=");

try{

Thread.sleep(3000);

}catch(Exception e){

e.printStackTrace();

}

sum+=increase;

out.println("sum");

out.close();

}

}

在AdderServlet中有一个实例变量sum,在AdderServlet的service()方法中提取increase请求参数,再把实例变量sum加上increase,最后再向客户端返回实例变量sum的值。为了延长响应客户请求的时间,在service()方法中调用Thread.sleep(3000)方法睡眠3秒钟。

在web.xml文件中为AdderServlet映射的URL为"/adder"。同时打开两个浏览器,分别输入如下URL:

http://localhost:8080/helloapp/adder?increase=100

http://localhost:8080/helloapp/adder?increase=200

两个浏览器并发访问AdderServlet,出现了奇怪的现象。在第二个浏览器中,客户端提供的请求参数increase的值为"200",AdderServlet返回"100+200=400",AdderServlet所做的加法运算显然是错误的。

在解决并发问题时,主要遵循以下原则:

●  根据实际应用需求,合理决定在Servlet中定义的变量的作用于。变量到底为实例变量,还是局部变量,是由实际应用需求决定的。

●  对于多个线程同时访问共享数据而导致并发问题的情况,使用Java同步机制对线程进行同步。

●  不提倡使用被废弃的javax.servlet.SingleThreadModel接口。