问题:
servlet在访问之后,就会执行实例化操作,创建一个Setvlet对象,而tomcat容器可以同时多个并发访问同一个setvlet,如果在方法中对成员变量进行修改,就会存在线程安全问题
代码演示:
public class SafeServlet extends HttpServlet {
private String message = "";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.接收参数
//2.调用业务逻辑,得到登陆结果
message = "访问成功";//访问失败
PrintWriter writer = resp.getWriter();
writer.println(message);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet( req,resp );
}
}
简单一点来说,就是如果小李和小王同时访问名为SafeServlet的servlet,当小王因为网络原因或者其他原因卡在了访问失败页面,而小李则访问成功了,此时SafeServlet中成员变量message的值就变为了访问成功,正在此时,小王卡住的原因解决了,此时小王就会发现自己虽然跳到访问成功页面,但是自己不能进行下一步操作。
那怎么样解决servlet线程安全问题呢?
解决线程安全问题有三种方式:
1.synchronized
将存在线程安全问题的代码放在同步代码开中
2.实现SingleThreadModel接口
servlet实现SingleThreadModel接口后,每一个线程都会创建一个servlet实例,这样每一个客户就不会存在资源的共享问题,但由于响应太低,已被淘汰
3.尽可能使用局部变量
synchronized:每一个客户进来都会等待上一个客户释放才会进入下一个客户,这样就会导致效率低下,试想一下,如果真的是一个高并发的程序,它的效率会怎样,所以此方式虽然可以解决问题,但是效率十分低下
public class SafeServlet extends HttpServlet {
private String message = "";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
synchronized (this) {
message = "访问成功";//访问失败
PrintWriter writer = resp.getWriter();
writer.println( message );
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet( req,resp );
}
}
实现SingleThreadModel接口:上面已经说了每一个线程都会创建一个servlet实例,每一个对象都会持有独有的一个对象,这样会导致时间、资源的浪费,因此此方式已经被淘汰了
public class SafeServlet extends HttpServlet implements SingleThreadModel {
private String message = "";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
message = "访问成功";
PrintWriter writer = resp.getWriter();
writer.println(message);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet( req,resp );
}
}
尽可能使用局部变量:该方法任何一个客户进来都拿一个局部变量,所以此方式即可以就解决性能问题又能解决线程安全问题,推荐使用
public class SafeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String message = "";
message = "访问成功";
PrintWriter writer = resp.getWriter();
writer.println(message);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet( req,resp );
}
}