Spring的Bean是线程安全的么?
一、概述
Spring容器本身并没有提供Bean的线程安全策略,所以可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体情况还是要结合Bean的作用域来讨论。
二、Bean的作用域
- singleton:默认作用域,单例bean,每个容器中只有一个bean的实例。
- prototype:为每一个bean请求创建一个实例。
- request:为每一个request请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
- session:与request范围类似,同一个session会话共享一个实例,不同会话使用不同的实例。
- application:bean定义在servletContext的生命周期中复用一个单例对象(跨容器)。
- global-session:全局作用域,所有会话共享一个实例。如果想要声明让所有会话共享的存储变量的话,那么这全局变量需要存储在global-session中。
三、Bean的线程安全分析
- 对于prototype作用域的Bean,每次都创建一个新对象,也就是线程之间不存在Bean共享,因此不会有线程安全问题。
- 对于singleton作用域的Bean,所有的线程都共享一个单例实例的Bean,因此是存在线程安全问题的。
但是如果单例Bean是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。解释一下:
- 无状态Bean(Stateless Bean):就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。
- 有状态Bean(Stateful Bean) :就是有实例变量的对象,可以保存数据,是非线程安全的。
对于有状态的bean(比如Model和View),就需要自行保证线程安全, 解决办法就是:
- 将有状态的bean的作用域由“singleton”改为“prototype”
- 采用ThreadLocal解决线程安全问题,为每个线程提供一个独立的变量副本
线程同步机制和ThreadLocal都是为了解决多线程中相同变量的访问冲突问题:
- 同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。
- ThreadLocal采用了“空间换时间”的方式。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。
版权声明:本文为qq_35958391原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。