不安全!Spring 容器本身并没有提供 Bean 的线程安全策略,可以说 Bean 本身不具备线程安全的特性。
通过 bean 的作用域解决方案:
(1)对于 prototype 作用域的 Bean,每次都会创建一个新的 Bean 对象,线程之间不存在共享,所以不会有线程安全问题。
(2)对于 singleton 作用域的 Bean,所有线程都共享一个单例对象,所以存在线程安全问题。如果单例 Bean 是无状态的,也就是线程中只涉及用 bean 对象调用方法的操作,如 Controller 类、Service 类和 Dao 类,那么这个单例 Bean 对象是线程安全的。
但如果单例 Bean 是有状态的,也就是涉及到保存数据的操作时,那么这个单例 Bean 是线程不安全的,需要自行保证线程安全,最直接的方式就是在 scope 中将有状态的 bean 的作用域由 “singleton” 改为 “prototype”。也可以采用 ThreadLocal 解决线程安全问题,为每一个线程提供一个独立的变量副本,不同线程只操作自己线程的变量副本。
有状态 Bean (Stateful Bean) :就是有实例变量的对象,可以保存数据,是非线程 安全的。
无状态 Bean (Stateless Bean):就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。
ThreadLocal 和线程同步机制(synchronize、Lock、CAS)都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了 “时间换空间” 的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而 ThreadLocal 采用了 “空间换时间” 的方式。ThreadLocal 会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。