Spring框架中的Bean是线程安全的吗?如果线程不安全,要如何处理?
Spring容器本身没有提供Bean的线程安全策略,因此,也可以说Spring容器中的bean不是线程安全的。
如何处理线程安全问题,分情况讨论:
Spring的作用域(scope):
singleton:单例,默认作用域。
prototype:原型,每次创建一个新对象。
request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下。
session:会话,同一个会话共享一个实例,不同会话使用不用的实例。
global-session:全局会话,所有会话共享一个实例。
线程安全问题:
1>对于prototype作用域,每次都生成一个新的对象,所以不存在线程安全问题。
2>对于singleton作用域,默认就是线程不安全的。但是对于开发中大部分的bean,其实都是无状态的,不需要保证线程安全。
无状态:表示这个实例没有属性对象,不能保存实数据,是不变的类。比如:controller、service、dao。
有状态:表示实例是有属性的对象,可以保存数据,是线程不安全的,比如:pojo。
但是如果要保证线程安全,可以将bean的作用域改为prototype,比如像Model View。
另外还可以采用ThreadLocal来解决线程安全问题。ThreadLocal为每个线程保存一个副本变量,每个线程只操作自己的副本变量。
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。