關於java Servlet,Struts,springMVC 的線程安全問題

如今主流的java的前端框架有:struts1,struts2,springmvc 還有最根本的servlet;前端

前些天一個朋友問我這方面的問題,就研究一番:java

1.關於struts1:spring

Struts1使用的ActionServlet是單例的,由這一個servlet處理全部.do請求。RequestProcessor也是單例。安全

RequestProcessor的processActionCreate方法:前端框架

/**
  * <p>Return an <code>Action</code> instance that will be used to process
  * the current request, creating a new one if necessary.</p>
  *
  * @param request  The servlet request we are processing
  * @param response The servlet response we are creating
  * @param mapping  The mapping we are using
  * @return An <code>Action</code> instance that will be used to process
  *         the current request.
  * @throws IOException if an input/output error occurs
  */
 protected Action processActionCreate(HttpServletRequest request,
     HttpServletResponse response, ActionMapping mapping)
     throws IOException {
     // Acquire the Action instance we will be using (if there is one)
     String className = mapping.getType();
     if (log.isDebugEnabled()) {
         log.debug(" Looking for Action instance for class " + className);
     }
     Action instance;
     // 這個同步快保證了Action的單例
     synchronized (actions) {
         // Return any existing Action instance of this class
         instance = (Action) actions.get(className);
         if (instance != null) {
             if (log.isTraceEnabled()) {
                 log.trace("  Returning existing Action instance");
             }
             return (instance);
         }
         // Create and return a new Action instance
         if (log.isTraceEnabled()) {
             log.trace("  Creating new Action instance");
         }
         try {
             instance = (Action) RequestUtils.applicationInstance(className);
             // Maybe we should propagate this exception
             // instead of returning null.
         } catch (Exception e) {
             log.error(getInternal().getMessage("actionCreate",
                     mapping.getPath()), e);
             response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                 getInternal().getMessage("actionCreate", mapping.getPath()));
             return (null);
         }
         actions.put(className, instance);
         if (instance.getServlet() == null) {
             instance.setServlet(this.servlet);
         }
     }
     return (instance);
 }

從結果能夠知道,是單例,既然是單例,若是當使用實例變量的時候就會有線程安全的問題;多線程

2.關於struts2
併發

咱們知道咱們使用struts2的時候,都是使用actionContext ;都是使用裏面的實例變量,讓struts2自動匹配成對象的。若是不是線程安全那全完了;因此struts2必須是線程安全的;由於每次處理一個請求,struts就會實例化一個對象;這樣就不會有線程安全的問題了;mvc

哦,忘記了一種狀況,struts2+spring來管理注入的時候;若是把action設置爲單例模式,就會出現問題;能夠把action設置爲prototype類型,還有一個辦法是設置做用域(具體沒有實驗過)app

參考來源框架


3.關於SpringMVC

SpringMVC的controller默認是單例模式的,因此也會有多線程併發的問題;

參考代碼:

@RequestMapping("/user")
@Controller
Class UserController
{
    @Resource
    UserService userService;

    @RequestMapping("/add")
    public void testA(User user){
        userService.add(user);
    }

    @RequestMapping("/get")
    public void testA(int id){
        userService.get(id);
    }
}

@Service("userService")
Class UserService{

    public static Map<Integer,User> usersCache = new HashMap<String,User>();

    public void add(User user){
        usersCache.put(user.getId(),user);
    }

    public void get(int id){
        usersCache.get(id);
    }

}

usersCache就是非線程安全的。

解決方法:

1)同步共享數據

2)不使用成員實例變量;

3)使用只讀數據


參考文章:

深刻研究Servlet線程安全性問題

Struts的線程安全問題

深刻研究Servlet線程安全性問題

相關文章
相關標籤/搜索