1. 程式人生 > >Spring併發訪問的執行緒安全性問題

Spring併發訪問的執行緒安全性問題

springmvc的controller是singleton的(非執行緒安全的),這也許就是他和struts2的區別吧
和Struts一樣,Spring的Controller預設是Singleton的,這意味著每個request過來,系統都會用原有的instance去處理,這樣導致了兩個結果:一是我們不用每次建立Controller,二是減少了物件建立和垃圾收集的時間;由於只有一個Controller的instance,當多個執行緒呼叫它的時候,它裡面的instance變數就不是執行緒安全的了,會發生竄資料的問題。

當然大多數情況下,我們根本不需要考慮執行緒安全的問題,比如dao,service等,除非在bean中聲明瞭例項變數。因此,我們在使用

spring mvc 的contrller時,應避免在controller中定義例項變數。 
如:

public class Controller extends AbstractCommandController {
......
protected ModelAndView handle(HttpServletRequest request,HttpServletResponse response,
			Object command,BindException errors) throws Exception {
company = ................;
}
protected Company company;
}

在這裡有宣告一個變數company,這裡就存在併發執行緒安全的問題。
如果控制器是使用單例形式,且controller中有一個私有的變數a,所有請求到同一個controller時,使用的a變數是共用的,即若是某個請求中修改了這個變數a,則,在別的請求中能夠讀到這個修改的內容。。

有幾種解決方法:
1、在控制器中不使用例項變數
2、將控制器的作用域從單例改為原型,即在spring配置檔案Controller中宣告 scope="prototype",每次都建立新的controller
3、在Controller中使用ThreadLocal變數

這幾種做法有好有壞,第一種,需要開發人員擁有較高的程式設計水平與思想意識,在編碼過程中力求避免出現這種BUG,而第二種則是容器自動的對每個請求產生一個例項,由JVM進行垃圾回收,因此做到了執行緒安全。

使用第一種方式的好處是例項物件只有一個,所有的請求都呼叫該例項物件,速度和效能上要優於第二種,不好的地方,就是需要程式設計師自己去控制例項變數的狀態保持問題。第二種由於每次請求都建立一個例項,所以會消耗較多的記憶體空間。
所以在使用spring開發web 時要注意,預設Controller、Dao、Service都是單例的。