對於使用過SpringMVC和Struts2的人來說,大家都知道SpringMVC是基於方法的攔截,而Struts2是基於類的攔截。struct2為每一個請求都實例化一個action所以不存在線程安全問題,springmvc默認單例請求使用一個Controller,假如這個Controller中定義了靜態變量,就會被多個線程共享。所以springmvc的controller不要定義靜態變量。如果要使用可以用ThreadLocal或者@Scope("prototype")開啟不以單例的模式運行但是以這種方式運行就不是單例了會有額外的開銷。那么有人就會問了,spring管理的bean默認也是單例的,是不是說除了controller,我后面的service和dao是也要注意線程安全問題?這個問題就要具體問題具體回答了,這里對線程安全問題的產生做個簡單的介紹也許你就會懂了。
我們都知道線程安全問題其實就是數據共享問題。如果多個線程之間共享了同一份數據就存在同時操作這個數據的可能。這個時候就會出現
和預期的偏差,這就是線程安全問題。
在談這個問題之前我們需要知道java內存哪些是多線程共享的,那些是線程獨有的。
Java平台中的內存包括以下幾種:Stack空間、Heap空間和Non-Heap空間,stack是線程獨享的,heap和non-heap是線程間共享的。
stack:棧,每個線程都有自己的棧,他主要用來存放局部變量的值即對象的引用。
heap:堆,所有的對象都是放到堆里面的,實例變量的值是存儲在Heap空間的。實例變量是可以被多線程共享的。
non-heap:靜態變量的值是存儲在Non-Heap空間中的,也是線程間共享的。
有如下的類:
class A{
private int a=0;
private static int b=1;
public void method(){
int c=0;
boolean flag = true;
List<String> list=new LinkedList<String>();
}}
}
其中a是實例變量會被多個線程共享(A類如果是singleton的話)
b是靜態變量(類變量)會被多個線程共享
c是局部變量用線程獨享的stack存放
list存放指向堆上的對象的引用也是線程獨享的
這里還實例化了一個LinkedList對象是放在heap上的這個是可以共享的,但是對例子上的這個對象來講
method每次被調用都會生成一個LinkedList實例,因此list變量所引用的對象實際上只有一個線程可以訪問。
到這里大家應該對使用單例還是多例有個明確的認識了吧。籠統的講當模式是單例的時候,而類里面有靜態變量和實例變量的時候要考慮線程安全問題了,這個時候的一些集合操作最好使用並發包java.util.concurrent里面的額相關集合類