对于使用过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里面的额相关集合类