Spring(十一):Spring Bean 是线程安全的吗?
Spring 中的默认为所有申明为 Bean
的对象创建一个实例存放到IoC
容器进行管理的,这些Bean
对象对于多线程来说是共享的,所以严格来说 Spring Bean 是非线程安全的。Spring 本身就没有对 bean 的多线程安全问题做出任何保证与措施。
作用域
Spring Bean 的线程安全还得根据应用场景和申明的作用范围来分析:
通常,对所有 有状态 Bean 申明为原型范围(protopyte),对无状态 Bean 申明为单例范围(singleton)。
- 有状态:有数据存储功能。如,定义了成员变量。
- 无状态:不会保存数据,就不存在状态被修改的情况。
单例
通常,Spring 默认创建的 Bean 是单例的(作用域:singleton),是一个无状态 Bean,不会因为多线程破坏对象状态,即访问线程不会对 Bean 的成员执行执行查询以外的操作,那么这个单例 Bean 可以认为是线程安全的。如 Controller、Service、Dao 等也是由 Spring 容器管理的,这类 Bean 大多是无状态的,只关注于方法本身。
原型
解决 Spring 中Bean
的线程安全问题,最简的办法是把Bean
的作用域由默认的singleton
修改为prototype
,每次调用都创建一个新的对象,但如果定义了静态成员变量,仍然不是线程安全的,静态成员变量会被改变。
对于每个bean的线程安全问题,根本原因是每个bean自身的设计。不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,那么就使用 ThreadLocal 把变量变为线程私有的;如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用synchronized、lock、CAS
等这些实现线程同步的方法了。
参考资料
Spring(十一):Spring Bean 是线程安全的吗?
http://blog.gxitsky.com/2018/04/01/Spring-11-bean-thread-safety/