由于Servlet是单例的,而一个Servlet对象可能同时处理多个请求,因此Servlet是线程不安全的。
@WebServlet(name = "ThreadServlet", urlPatterns = "/ThreadServlet")
public class ThreadServlet extends HttpServlet {
String name;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
String threadName = Thread.currentThread().getName();
name = threadName;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "________" + name);
}
}
以上案例代码,在多线程中会出现线程不安全,因为多个线程同时访问的是同一个成员变量,会共享该实例变量,而在访问局部变量时,每个线程都会有自己的变量,不会被共享。
故,servlet在多线程中不安全
解决Servlet线程安全问题
1、最简单的方式,不使用成员变量,使用局部变量即可
@WebServlet(name = "ThreadServlet2", urlPatterns = "/ThreadServlet2")
public class ThreadServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
String name;
String threadName = Thread.currentThread().getName();
name = threadName;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "________" + name);
}
}
2、使用synchronized关键字加锁来解决servlet线程安全问题
@WebServlet(name = "ThreadServlet3", urlPatterns = "/ThreadServlet3")
public class ThreadServlet3 extends HttpServlet {
String name;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
synchronized (this) {
String threadName = Thread.currentThread().getName();
name = threadName;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "________" + name);
}
}
}
3、使用ThreadLocal来解决线程不安全
@WebServlet(name = "ThreadServlet4", urlPatterns = "/ThreadServlet4")
public class ThreadServlet4 extends HttpServlet {
String name;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
ThreadLocal<String> local = new ThreadLocal<>();
String threadName = Thread.currentThread().getName();
name = threadName;
local.set(name);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "________" + local.get());
}
}
总结:在Servlet线程安全问题中,尽可能不创建成员变量。
Q.E.D.