Bean的线程安全分析
- 对于prototype作用域的Bean,每次都创建一个新对象,也就是线程之间不存在Bean共享,因此不会有线程安全问题。
- 对于singleton作用域的Bean,所有的线程都共享一个单例实例的Bean,因此是存在线程安全问题的。
但是如果单例Bean是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。解释一下:
- 无状态Bean(Stateless Bean):就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。
- 有状态Bean(Stateful Bean) :就是有实例变量的对象,可以保存数据,是非线程安全的。
对于有状态的bean(比如Model和View),就需要自行保证线程安全, 解决办法就是:
- 将有状态的bean的作用域由“singleton”改为“prototype”
- 采用ThreadLocal解决线程安全问题,为每个线程提供一个独立的变量副本
spring中bean的线程安全问题
结合Spring来理解,Spring的Bean默认都是单例的,那么会不会有线程安全的问题,要知道线程安全是针对不同用户之间对成员变量的操作互相影响导致的,换句话说如果你的类中没有非静态成员变量 ,即使有多个线程同时访问单例对象的成员方法也不会出问题,因为每个线程在栈和方法区中会有私有的存储空间,并不会导致数据混乱出现类似事务ACID的问题,写到这里大家可能已经明白了,线程安全只是针对全局变量的,如果是方法的话用同一个对象同时进行调用也不会出现安全问题。Service和DAO的实例对象大多数情况下只是作一个方法的调用,在Service的实现类中如果有全局变量怎么办呢?
线程同步机制和ThreadLocal都是为了解决多线程中相同变量的访问冲突问题:
同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。 ThreadLocal采用了“空间换时间”的方式。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。
有状态和无状态的对象区别
第一:基本概念
-
有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。 -
无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象.不能保存数据,是不变类,是线程安全的。
第二:看看代加深影响
public class StatefulBean {
public int state;
public User user;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
public class StatelessBeanService {
BillDao billDao;
public BillDao getBillDao() {
return billDao;
}
public void setBillDao(BillDao billDao) {
this.billDao = billDao;
}
public List<User> findUser(String Id) {
return null;
}
}
第三:Spring中的有状态(Stateful)和无状态(Stateless)
-
通过上面的分析,相信大家已经对有状态和无状态有了一定的理解。无状态的Bean适合用不变模式,技术就是单例模式,这样可以共享实例,提高性能。有状态的Bean,多线程环境下不安全,那么适合用Prototype原型模式。Prototype: 每次对bean的请求都会创建一个新的bean实例。 -
默认情况下,从Spring bean工厂所取得的实例为singleton(scope属性为singleton),容器只存在一个共享的bean实例。 -
理解了两者的关系,那么scope选择的原则就很容易了:有状态的bean都使用prototype作用域,而对无状态的bean则应该使用singleton作用域。 -
如Service层、Dao层用默认singleton就行,虽然Service类也有dao这样的属性,但dao这些类都是没有状态信息的,也就是相当于不变(immutable)类,所以不影响。Struts2中的Action因为会有User、BizEntity这样的实例对象,是有状态信息的,在多线程环境下是不安全的,所以Struts2默认的实现是Prototype模式。在Spring中,Struts2的Action中,scope要配成prototype作用域。
|