Spring管理的Bean对象默认是单例模式,存在线程安全问题。
在什么情况下,单例的Bean对象存在线程安全问题
- 对于原型Bean,每次创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。
- 如果单例Bean,是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。
- 对于单例Bean,当Bean对象对应的类存在可变的成员变量并且其中存在改变这个变量的线程时,多线程操作该Bean对象时会出现线程安全。
原因
当多线程中存在线程改变了bean对象的可变成员变量时,其他线程无法访问该bean对象的初始状态,从而造成数据错乱。
解决办法
-
在Bean对象中尽量避免定义可变的成员变量;
-
在bean对象中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中
使用ThreadLocal的好处
使得多线程场景下,多个线程对这个单例Bean的成员变量并不存在资源的竞争,因为ThreadLocal为每个线程保存线程私有的数据。