Servlet容器采用了单实例多线程的方式(Servlet容器默认的设置),这样可以减少创建实例的开销,提高效率。
但是在多线程方面也埋下了不少隐患,需要开发者格外小心。
(一)变量的安全性
错误实例:
public class test extends HttpServlet{ String user = "" ; public void doGet(HttpServletRequest req , HttpServletResponse res) throws ServletException , IOException{ user = req.getParameter("user"); ...... } }
例如:a、b同时访问这个servlet,a提交的user=aaa,b提交的user=bbb。
首先,servlet容器分配一个线程T-a来处理请求a,获取其user的值aaa,并赋给变量user。此时T-a时间片到了,servlet容器分配另外一个线程T-b来处理请求b,
获取其user的值bbb,并覆盖变量user,当T-a线程重新获取执行权时,user已经“物是人非”了。
这里可以类比:jdbc的事务管理,“丢失更新”和这个场景类似。
解决方案:
1)定义本地变量,将user在doGet方法中定义。
因为user是本地变量,每一个线程都有user变量的拷贝,彼此不受影响。
2)设置方法同步(或者同步块)
因为设置了同步,可以防止多个线程同时调用doGet方法。但是所有请求该servlet的“请求”将串行处理,影响效率。