Spring中单例和多例的深⼊理解
Spring单例和多例的理解
实例化bean的三种方式1、什么是单例和多例
单例:所有请求⽤同⼀个对象来处理。通过单例模式,可以保证系统中⼀个类只有⼀个实例。
多例:每个请求⽤⼀个新的对象来处理。
2、Spring中的单例与多例
spring ioc容器的bean都是默认单例的,即spring依赖注⼊Bean实例默认是单例的。
spring提供了5中scope,分别是singleton,prototype,request,session,global session,常⽤是前两种。点此查看官⽹介绍。
单例bean与多例(原型)bean的区别:
如果⼀个bean被声明为单例的时候,在处理多次请求的时候,在spring容器⾥只实例化出⼀个bean,后续的请求都公⽤这个对象,这个对象会保存在⼀个map⾥⾯。
当有请求来的时候,会先从缓存(map)⾥查看有没有,有的话直接使⽤这个对象,没有的话才实例化⼀个新的对象,所以这是个单例的。
但是对于原型(prototype)bean来说,当每次请求来的时候,会直接实例化新的bean,没有缓存以及缓存查询的过程。
3、单例的优势与劣势
优势:
由于不会创建新的对象,所以有以下⼏个性能上的优势:
减少新⽣成实例的消耗。新⽣成实例包括两个⽅⾯,第⼀,spring会通过反射或者cglib来⽣成bean实例,这都是耗性能的操作。第⼆,给对象分配内存也会涉及负责算法。
减少jvm垃圾回收。由于不会给每个请求都⽣成bean实例,所以回收的对象就少了。
可以快速获取到bean。因为单例获取bean操作,除了第⼀次⽣成之外,其余都是从缓存⾥获取的,所以很快。
劣势:
⼀个很⼤的劣势是它不能做到线程安全。由于所有请求都共享⼀个bean实例,那么如果这个bean是⼀个有状态的bean的话,在并发场景下就有可能出现问题。
4、spring单例模式与线程安全:
当多⽤户同时请求⼀个服务时,容器会给每⼀个请求分配⼀个线程,这时多个线程会并发执⾏该请求所对应的业务逻辑(成员⽅法),此时就要注意了,如果该处理逻辑中有对该单例状态的修改(体现为该单例的成员属性),则必须考虑线程同步问题(此时该状态就是⼀个临界资源(共享数据),如果多个线程同时操作(修改)这个临界资源就会诱发线程安全问题)。
线程安全:如果你的代码所在的进程中有多个线程在同时运⾏,⽽这些线程可能会同时运⾏这段代码。如果每次运⾏的结果和单线程运⾏的结果是⼀样的,⽽且其他的变量的值也和预期的是⼀样的,就是线程安全的。或者说:⼀个类或者程序所提供的接⼝对于线程来说是原⼦操作,或者多线程之间的切换不会导致该接⼝的执⾏结果存在⼆义性,就是线程安全的。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量,静态变量只有读操作,⽽⽆写操作,⼀般来说,这个全局变量是线程安全的;若多个线程同时执⾏写操作,⼀般都需要考虑线程同步,否则就可能影响线程安全。
常量始终是线程安全的,因为只存在读操作;
每次调⽤⽅法前都新建⼀个实例是线程安全的,因为不会访问共享的资源;
局部变量是线程安全的。因为每执⾏⼀个⽅法,都会在独⽴的空间创建局部变量,它不是共享资源。局部变量包括⽅法的参数变量和⽅法内的变量。
在关于spring单例与线程安全的很多⽂章中,会提到⼀个概念,即有状态bean和⽆状态bean。
⽆状态bean:⽆状态,就是⼀次操作,不能保存数据。⽆状态bean,就是没有实例变量的对象,不能保存数据,是不变类,在线程安全的。
有状态bean:有状态,就是有数据存储功能。有状态bean,就是有实例变量的对象,可以保存数据,是⾮线程安全的。
如何解决线程安全问题?
(1)使⽤线程同步机制:通过对象的锁机制保证同⼀时间只有⼀个线程访问变量。这时该变量是多个线程共享的,使⽤同步机制要求程序缜密地分析什么时候对变量进⾏读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂问题,程序设计和编写难度相对较⼤。
(2)使⽤ThreadLocal:为每⼀个线程提供⼀个独⽴的变量副本,从⽽隔离了多个线程对数据的访问冲突。因为每⼀个线程都拥有⾃⼰的变量副本,从⽽也就没有必要对该变量进⾏同步了。
概括起来就是:对于多线程资源共享的问题,同步机制采⽤了“以时间换空间”的⽅式,⽽ThreadLocal采⽤了“以空间换时间”的⽅式。前者仅提供⼀份变量,让不同的线程排队访问,⽽后者为每⼀个线程都提供了⼀份变量,因此可以同时访问⽽互不影响。
5、单例如何变多例
Scope声明为prototype,即
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
SpringMVC单例和多例的优缺点
默认是单例模式可设置为多例模式,两种模式的优缺点:
1、单例模式(单例多线程的)
优点:共享⼀个实例,内存占⽤少,GC开销⼩
缺点:共享资源存在线程安全问题
2、多例模式(单线程的)
优点:不存在线程安全问题(静态共享资源除外)
缺点:多个实例,内存占⽤多,GC开销⼤
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论