1. 程式人生 > >Spring MVC 執行緒安全問題的思考

Spring MVC 執行緒安全問題的思考

在讀一些博文的時候發現有些文章對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來儲存類變數,將類變數儲存線上程的變數域中,讓不同的請求隔離開來

這裡寫圖片描述
如果我的方法有幫到你,不妨請杯水喝吧?