Spring容器本身並沒有提供Bean的線程安全策略,因此可以說Spring容器中的Bean本身不具備線程安全的特性,但是具體情況還是要結合Bean的作用域來討論。
(1)對於prototype作用域的Bean,每次都創建一個新對象,也就是線程之間不存在Bean共享,因此不會有線程安全問題。
(2)對於singleton作用域的Bean,所有的線程都共享一個單例實例的Bean,因此是存在線程安全問題的。但是如果單例Bean是一個無狀態Bean,也就是線程中的操作不會對Bean的成員執行查詢以外的操作,那么這個單例Bean是線程安全的。比如Controller類、Service類和Dao等,這些Bean大多是無狀態的,只關注於方法本身。
有狀態Bean(Stateful Bean) :就是有實例變量的對象,可以保存數據,是非線程安全的。
無狀態Bean(Stateless Bean):就是沒有實例變量的對象,不能保存數據,是不變類,是線程安全的。
對於有狀態的bean(比如Model和View),就需要自行保證線程安全,最淺顯的解決辦法就是將有狀態的bean的作用域由“singleton”改為“prototype”。
也可以采用ThreadLocal解決線程安全問題,為每個線程提供一個獨立的變量副本,不同線程只操作自己線程的副本變量。
ThreadLocal和線程同步機制都是為了解決多線程中相同變量的訪問沖突問題。同步機制采用了“時間換空間”的方式,僅提供一份變量,不同的線程在訪問前需要獲取鎖,沒獲得鎖的線程則需要排隊。而ThreadLocal采用了“空間換時間”的方式。ThreadLocal會為每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了。