看到這樣一個問題:spring框架中的單例Beans是線程安全的么?
Spring框架並沒有對單例bean進行任何多線程的封裝處理。關於單例bean的線程安全和並發問題需要開發者自行去搞定。但實際上,大部分的Spring bean並沒有可變的狀態(比如Serview類和DAO類),所以在某種程度上說Spring的單例bean是線程安全的。如果你的bean有多種狀態的話(比如 View Model 對象),就需要自行保證線程安全。
最淺顯的解決辦法就是將多態bean的作用域由“singleton”變更為“prototype”。
沒太看懂有狀態和無狀態的bean是什么意思,於是百度之,獲益匪淺。
在Spring的Bean配置中,存在這樣兩種情況:
- <bean id="testManager" class="com.sw.TestManagerImpl" scope="singleton" />
- <bean id="testManager" class="com.sw.TestManagerImpl" scope="prototype" />
當然,scope的值不止這兩種,還包括了request,session 等。但用的最多的還是singleton單態,prototype多態。
singleton表示該bean全局只有一個實例,Spring中bean的scope默認也是singleton.
prototype表示該bean在每次被注入的時候,都要重新創建一個實例,這種情況適用於有狀態的Bean.
對於SSH架構的系統,很少關心這方面,因為我們用到的一般都是singleton. Bean的注入由Spring管理。
對於有狀態的Bean呢?
下面是一個有狀態的Bean
- package com.sw;
- public class TestManagerImpl implements TestManager{
- private User user;
- public void deleteUser(User e) throws Exception {
- user = e ; //1
- prepareData(e);
- }
- public void prepareData(User e) throws Exception {
- user = getUserByID(e.getId()); //2
- .....
- //使用user.getId(); //3
- .....
- .....
- }
- }
如果該Bean配置為singleton,會出現什么樣的狀況呢?
如果有2個用戶訪問,都調用到了該Bean.
假定為user1,user2
當user1 調用到程序中的1步驟的時候,該Bean的私有變量user被付值為user1
當user1的程序走到2步驟的時候,該Bean的私有變量user被重新付值為user1_create
理想的狀況,當user1走到3步驟的時候,私有變量user應該為user1_create;
但如果在user1調用到3步驟之前,user2開始運行到了1步驟了,由於單態的資源共享,則私有變量user被修改為user2
這種情況下,user1的步驟3用到的user.getId()實際用到是user2的對象。
而如果是prototype的話,就不會出現資源共享的問題。
對於SSH來說,Bean的配置是沒錯的,配置為singleton ;實際應該是這個例子不應該用私有變量。這樣就使得這個Bean
由無狀態變成了有狀態Bean.還是應該盡量使用無狀態Bean.如果在程序中出現私有變量,盡量替換為參數。
對於每個訪問私有變量的方法增加變量傳入或者通過ThreadLocal來獲取也是不錯的方法。
真正出現上面代碼問題的也是少數,出現的時候,一般是為了圖方便,一個很多方法都要用到的變量,如果都需要用參數的
方式傳遞多麻煩呀,這樣私有變量多好,不用參數那樣丑陋。但是丑陋並不代表不好,以對的,自己習慣的方式編程,才能
盡量避免問題的發生。