JAVA 併發編程- Spring 併發訪問的線程安全性問題

   首先對於Spring的IOC來講,對象是由Spring來幫咱們管理,也就是在Spring啓動的時候,在Spring容器中,由Spring給咱們建立的,Spring會幫咱們維護,通常都是單例的,也就是一個對象。html


spring生成對象默認是單例的。經過scope屬性能夠更改成多例。java


第一部分:驗證Spring生成對象默認是單例的。


下面咱們來一個網上的例子驗證一下:web

<bean id="singleton" class="java.util.Date" scope="singleton"></bean>  
<bean id="prototype" class="java.util.Date" scope="prototype"></bean>
package test;   
import java.util.Date;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
import com.opensymphony.xwork2.ActionContext;  
public class TestScope {  
    public static void main(String[] args) {  
       ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext-web.xml");  
       Date s1=(Date)context.getBean("singleton");  
       Date p1=(Date)context.getBean("prototype");  
       Date s2=(Date)context.getBean("singleton");  
       Date p2=(Date)context.getBean("prototype");  
   System.out.println("單例:"+(s1==s2));  
  System.out.println("非單例:"+(p1==p2));  
    } 
}



輸出結果:

結果ajax

單例:truespring

非單例:false編程


注:複合數據類型的「== 」對比的是內存中存放的地址,因此此處咱們採用「==」去對比安全

由於object中的equals初始行爲是比較內存中的地址,但在一些類庫中被覆蓋掉了如(String,Integer,Date等)restful


第二部分:SpringMVC和Struts2中是併發訪問否會存在線程安全問題。


對於使用過SpringMVC和Struts2的人來講,你們都知道SpringMVC是基於方法的攔截,而Struts2是基於類的攔截。網絡


對於Struts2來講,由於每次處理一個請求,struts就會實例化一個對象;這樣就不會有線程安全的問題了;架構

而Spring的controller默認是Singleton的,這意味着每個request過來,系統都會用原有的instance去處理,這樣致使兩個結果:

一是咱們不用每次建立Controller,二是減小了對象建立和垃圾收集的時間;因爲只有一個Controller的instance,當多個線程調用它的時候,它裏面的instance變量就不是線程安全的了,會發生竄數據的問題。


固然大多數狀況下,咱們根本不須要考慮線程安全的問題,好比dao,service等,除非在bean中聲明瞭實例變量。所以,咱們在使用spring mvc 的contrller時,應避免在controller中定義實例變量。 

如:

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

 解決方案:

有幾種解決方法:
一、在Controller中使用ThreadLocal變量
二、在spring配置文件Controller中聲明 scope="prototype",每次都建立新的controller
所在在使用spring開發web 時要注意,默認Controller、Dao、Service都是單例的。


例如:

@Controller  
@RequestMapping("/fui")  
public class FuiController extends SpringController {  
//這麼定義的話就是單例  
  
@Controller  
@Scope("prototype")  
@RequestMapping("/fui")  
public class FuiController extends SpringController {  
//每次都建立

第三部分:springMVC與struts2的區別。

下面是從網絡上摘抄的一段對比,你們能夠看看點擊打開連接

1. 機制:spring mvc的入口是servlet,而struts2是filter,這樣就致使了兩者的機制不一樣。 

2. 性能:spring會稍微比struts快。spring mvc是基於方法的設計,而sturts是基於類,每次發一次請求都會實例一個action,每一個action都會被注入屬性,而spring基於方法,粒度更細,但要當心把握像在servlet控制數據同樣。spring3 mvc是方法級別的攔截,攔截到方法後根據參數上的註解,把request數據注入進去,在spring3 mvc中,一個方法對應一個request上下文。而struts2框架是類級別的攔截,每次來了請求就建立一個Action,而後調用setter getter方法把request中的數據注入;struts2其實是經過setter getter方法與request打交道的;struts2中,一個Action對象對應一個request上下文。 

3. 參數傳遞:struts是在接受參數的時候,能夠用屬性來接受參數,這就說明參數是讓多個方法共享的。

4. 設計思想上:struts更加符合oop的編程思想, spring就比較謹慎,在servlet上擴展。 

5. intercepter的實現機制:struts有以本身的interceptor機制,spring mvc用的是獨立的AOP方式。這樣致使struts的配置文件量仍是比spring mvc大,雖然struts的配置能繼承,因此我以爲論使用上來說,spring mvc使用更加簡潔,開發效率Spring MVC確實比struts2高。spring mvc是方法級別的攔截,一個方法對應一個request上下文,而方法同時又跟一個url對應,因此說從架構自己上spring3 mvc就容易實現restful url。struts2是類級別的攔截,一個類對應一個request上下文;實現restful url要費勁,由於struts2 action的一個方法能夠對應一個url;而其類屬性卻被全部方法共享,這也就沒法用註解或其餘方式標識其所屬方法了。spring3 mvc的方法之間基本上獨立的,獨享request response數據,請求數據經過參數獲取,處理結果經過ModelMap交回給框架方法之間不共享變量,而struts2搞的就比較亂,雖然方法之間也是獨立的,但其全部Action變量是共享的,這不會影響程序運行,卻給咱們編碼,讀程序時帶來麻煩。 

6. 另外,spring3 mvc的驗證也是一個亮點,支持JSR303,處理ajax的請求更是方便,只需一個註解@ResponseBody ,而後直接返回響應文本便可。

總結:

這樣也說明了SpringMVC還有Servlet都是方法的線程安全,因此在類方法聲明的私有或者公有變量不是線程安全的,而struts2的確實是線程安全的。


第四部分:那麼對於Struts2+Spring來管理注入的時候呢?

Struts2它是多實例的,對於每一個請求都會生成1個實例,spring默認是單實例的(下面針對Struts與Spring集成的兩種方式分別來介紹struts2和spring的兩種整合方式

一:對於無Spring插件(Struts2-spring-plugin-XXX.jar)的整合方式,須要在spring的action Bean中加業務邏輯控制器類配scope="prototype"。

<bean id="user" class="modle.User" scope="prototype"></bean>  

二:對於有Spring插件(Struts2-spring-plugin-XXX.jar)的整合方式:反編譯StrutsSpringObjectFactory以及相關的代碼才發現,若是在struts action的配置文件中<action name=".." class=".."/>中class寫的若是是完整的包名和類名的話就是struts建立action對象,也就是多實例的;


總結:若是是spring配置文件中的 bean的名字的話就是spring建立,那麼單實例仍是多實例就由spring的action Bean中的業務邏輯控制器類是否配置爲scope=」prototype」,有就是多實例的,沒有就是單實例的,順序是先從spring中找,找不到再從struts配置文件中找。

相關文章
相關標籤/搜索