一、问题
对于实例变量来说,由于servlet在Tomcat中是以单例模式存在的,所有的线程共享实例变量。多个线程对共享资源的访问造成了线程不安全问题。
案例如下:
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloWorldServlet extends HttpServlet
{
String message;
/**
*
*/
private static final long serialVersionUID = 787553024399133588L;
public void service(HttpServletRequest request,HttpServletResponse response) throws IOException{
message =request.getParameter("message");
PrintWriter pw = response.getWriter();
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
pw.write("<div><strong>Hello World</strong>!</div>"+message);
pw.close();
}
}
在构建好的工程部署到本地Tomcat下,启动Tomcat,打开俩个浏览器
访问1: http://localhost:8080/Servlet03/HelloWorld?message=helloA
访问2: http://localhost:8080/Servlet03/HelloWorld?message=helloB
分别刷新访问,在访问第一个地址的页面打印出了helloB,在访问第二个地址的时候页面有时候会打印出helloA。这个就是高并发下的多线程的安全问题。
二、解决方式:
- 添加同步代码锁 synchronized
- 将要访问的实例变量改为局部变量(多线程下每个线程对局部变量都会有自己的一份copy,这样对局部变量的修改只会影响到自己的copy而不会对别的线程产生影响,线程安全的)
三、补充
struts1 因为是基于servlet开发的框架,存在安全隐患。所以才催生来后来的struts2(基于filter,摆脱了线程安全问题),但技术上二者并无多少联系,分别属于两个开发团队。