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

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

好像是在去年畢業面試的時候,面試官問了我這個問題,如何保證Spring併發訪問的執行緒安全問題,當時的我也只是對這些有所瞭解,僅僅知道spring中的controller、serivce、dao預設為單例,只要不在這些單例中使用成員變數就可以了,然後工作至今,我還是對其中原理有些模糊,遂今天總結一下。

為什麼spring併發訪問可能會有安全性問題?

多執行緒指的是同一段程式碼,有多個不同的執行緒一起執行,這種情況下我們編碼的時候就要有意識的去注意多執行緒可能造成的資料安全問題。

在spring中,預設的controller、service、dao都是單例的,並且是交由spring容器進行統一管理的,這樣做的好處一來是減少了例項的建立次數,降低了系統的開銷,二來是將spring框架各個層解耦,由spring容器來例項化並且注入物件,降低了系統的複雜度。

當然,spring也可以生成多例項的bean,只需要將scope設定為"prototype"。

但是單例在多執行緒環境下,是被多個執行緒共享的,那麼這個單例物件的成員變數就是可以被多個執行緒同時操作的,比如說A執行緒修改了成員變數,而B執行緒讀取到的卻是A執行緒修改之前的成員變數,這就可能導致資料安全問題。

如何去避免執行緒安全問題?

執行緒安全問題在spring中,因為bean建立預設為單例模式,所以可能會因為成員變數的共享而導致安全問題,我們可以儘量不在單例中使用成員變數,這樣就規避了多執行緒安全問題。

或者我們也可以對我們所使用的成員變數進行加鎖,限制該變數在同一時間裡只有一個執行緒能夠操作。

又或者我們可以將spring中bean建立的模式改成普通的,可以同時存在多個例項的模式,這樣也不會造成多執行緒安全問題,但是這樣做了之後系統會增加很多例項的建立與銷燬還有垃圾回收機制所造成的系統開銷。

我們還可以通過ThreadLocal來實現執行緒安全。

為什麼spring單例模式下不使用成員變數可以規避多執行緒安全問題?

因為單例的物件中的成員變數是被多個執行緒共享的變數,所有執行緒都能對該單例成員變數進行操作,而我們單例中的方法中所傳遞的變數是區域性變數,區域性變數的生命週期僅僅存在於方法執行的開始到結束,對於每個執行緒來說,區域性變數都是獨有的,互相不可見的。所以只要我們在單例中不定義使用成員變數,這樣便不會造成多執行緒直接資料安全性問題。