多線程並發執行同一段代碼時,若每次運行結果與單線程一致,且共享變量值符合預期,則稱線程安全。反之則線程不安全。
Servlet 默認單例,多請求共享實例變量:
public class ThreadSafeServlet extends HttpServlet {
private String name; // 共享變量!
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
name = req.getParameter("name");
Thread.sleep(10000);
resp.getWriter().print("name=" + name);
}
}
10 秒內並發訪問 ?name=zhangSan 和 ?name=liSi,兩者輸出均為 name=liSi —— 數據競爭導致錯誤。
解決:將變量移至方法局部,或僅定義 final 不變對象。
Struts2 為每個 HTTP 請求創建一個新的 Action 實例(Prototype 作用域)。
<bean scope="prototype"> 或 @Scope("prototype")。| 框架 | 實例策略 | 線程安全性 | 應對措施 |
|---|---|---|---|
| Servlet | 單例 | 不安全 | 避免實例變量,用局部變量/ThreadLocal |
| Struts2 | 每請求一實例 | 安全 | 無需特殊處理 |
| Spring MVC | 默認單例 Controller | 不安全 | 同 Servlet,避免實例變量 |