Spring MVC 執行緒安全問題的思考
阿新 • • 發佈:2019-01-07
在讀一些博文的時候發現有些文章對SpringMVC的Controller執行緒安全的驗證並不正確,比如沒有探究controller執行緒不安全的具體原因,比如將請求執行緒當做controller多例的證明,以下將驗證。 http://bbs.csdn.net/topics/390894585 http://bbs.csdn.net/topics/390891861#post-398241838
1.request請求執行緒與controllte的關係是什麼?
簡易的驗證方法程式碼
在網上隨便下載了一個壓力測試工具
測試結果如下
從列印的日誌可以看出,請求時多執行緒請求的,但是每次請求過來呼叫的Controller物件都是一個,而不是一個請求過來就建立一個controller物件
那為什麼說controller是不安全的呢?
原因就在於如果這個controller物件是單例的,那麼如果不小心在類中定義了類變數,那麼這個類變數是被所有請求共享的,這可能會造成多個請求修改該變數的值,出現與預期結果不符合的異常。
接下來將驗證多併發的情況下controller的執行緒不安全的具體表現、通過配置實現controller多例
在單例的情況下 相當於所有類變數對於每次請求都是共享的,每一次請求對類變數的修改都是有效的
看一下列印的日誌private static int st=0; private int index=0; @RequestMapping(value="/testcontrollersinglon",method=RequestMethod.GET) @ResponseBody public String testControllerSinglon(HttpServletRequest request){ try { System.out.println(st++ + " | " + index++); return "yes"; } catch (Exception e) { e.printStackTrace(); return "error"; } }
通過日誌可以看出 變數index為所有請求共享
那有沒有辦法讓controller不以單例而以每次請求都重新建立的形式存在呢?
答案是當然可以,只需要在類上添加註解@Scope("prototype")即可,這樣每次請求呼叫的類都是重新生成的(每次生成會影響效率)
新增@Scope("prototype")後我們再看看日誌就會看出區別了
雖然這樣可以解決問題,但增加了時間成本,總讓人不爽,還有其他方法麼?答案是肯定的!使用ThreadLocal來儲存類變數,將類變數儲存線上程的變數域中,讓不同的請求隔離開來
如果我的方法有幫到你,不妨請杯水喝吧?