Spring中单例和多例的深入理解

Spring单例和多例的理解

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开销大

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 浅谈Spring 的Controller 是单例or多例

    背景:今天写代码遇到一个Controller 中的线程安全问题,那么Spring 的Controller 是单例还是多例的呢?若为单例又如何保证并发安全呢? 一.面试回答 Spring管理的Controller,即加入@Controller 注入的类,默认是单例的,因此建议: 1.不要在Controller 中定义成员变量:(单例非线程安全,会导致属性重复使用) 2.若必须要在Controller 中定义一个非静态成员变量,则通过注解@Scope("prototype"),将其设置为多

  • 浅谈Spring单例Bean与单例模式的区别

    Spring单例Bean与单例模式的区别在于它们关联的环境不一样,单例模式是指在一个JVM进程中仅有一个实例,而Spring单例是指一个Spring Bean容器(ApplicationContext)中仅有一个实例. 首先看单例模式,在一个JVM进程中(理论上,一个运行的JAVA程序就必定有自己一个独立的JVM)仅有一个实例,于是无论在程序中的何处获取实例,始终都返回同一个对象,以Java内置的Runtime为例(现在枚举是单例模式的最佳实践),无论何时何处获取,下面的判断始终为真: // 基

  • 通过spring注解开发,简单测试单例和多例区别

    目录 通过spring注解开发,测试单例和多例区别 1.注解和配置两种用法形式 2.在spring框架中,scope作用域默认是单例的 3.实例 (1)多例: (2)单例(注解版) Spring中单例和多例的理解 1.什么是单例和多例 2.Spring中的单例与多例 单例bean与多例(原型)bean的区别: 3.单例的优势与劣势 优势: 劣势: 4.spring单例模式与线程安全: 如何解决线程安全问题? 5.单例如何变多例 通过spring注解开发,测试单例和多例区别 1.注解和配置两种用法

  • Spring框架中 @Autowired 和 @Resource 注解的区别

    Spring框架中 @Autowired 和 @Resource 注解的区别 在 spring 框架中,除了使用其特有的注解外,使用基于 JSR-250 的注解,它包括 @PostConstruct, @PreDestroy 和 @Resource 注释. 首先,咱们简单了解 @PostConstruct 和 @PreDestroy 注释: 为了定义一个 bean 的安装和卸载,我们可以使用 init-method 和 destroy-method 参数简单的声明一下 ,其中 init-meth

  • 浅谈Spring中单例Bean是线程安全的吗

    Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean去研究. Spring 的 bean 作用域(scope)类型 1.singleton:单例,默认作用域. 2.prototype:原型,每次创建一个新对象. 3.request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下. 4.session:会话,同一个会

  • Spring中单例和多例的深入理解

    Spring单例和多例的理解 1.什么是单例和多例 单例:所有请求用同一个对象来处理.通过单例模式,可以保证系统中一个类只有一个实例. 多例:每个请求用一个新的对象来处理. 2.Spring中的单例与多例 spring ioc容器的bean都是默认单例的,即spring依赖注入Bean实例默认是单例的. spring提供了5中scope,分别是singleton,prototype,request,session,global session,常用是前两种.点此查看官网介绍. 单例bean与多例

  • 关于spring中单例Bean引用原型Bean产生的问题及解决

    目录 spring单例Bean引用原型Bean产生的问题及解决 问题描述 为了更直观的发现问题,下面我们用代码演示一遍 问题分析 spring Bean的几个相关问题 1.Spring Bean 作用域 2.什么是Spring inner beans 3.什么是有状态.无状态 4.Spring框架中的单例Bean是线程安全的么 5.Spring Bean 的自动装配 6.各种自动装配模式的区别 7.在Spring中可以注入null或空字符串吗 8.Spring框架中有哪些不同类型的事件(都继承自

  • spring中向一个单例bean中注入非单例bean的方法详解

    目录 前言 错误实例演示 实现ApplicationContextAware接口 lookup method lookup method签名 总结 前言 看到这个题目相信很多小伙伴都是懵懵的,平时我们的做法大都是下面的操作 @Component public class People{ @Autowired private Man man; } 这里如果Man是单例的,这种写法是没有问题的,但如果Man是原型的,这样是否会存在问题. 错误实例演示 这里有一个原型(生命周期为prototype)的

  • Spring bean配置单例或多例模式方式

    目录 Spring bean配置单例或多例模式 单例 多例 Spring scope配置单例.多例模式 1.scope属性介绍 2.scope配置 3.单例模式底层实现模拟 Spring bean配置单例或多例模式 单例 spring bean 默认是单例默认,在对应.xml文件中的配置是: <bean id="user" class="..." scope="singleton"/> singleton就是配置这个bean是否是单例

  • Spring中Bean的单例和多例使用说明

    目录 Bean的单例和多例使用 实战演示 Spring单例bean与原型bean区别和创建过程 singletonScope与prototypeScope Bean的单例和多例使用 在Spring中,bean可以被定义为两种模式:prototype(多例)和singleton(单例) singleton(单例):只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一的实例. prototype(多例):对这个bean的每次请求都会创建一个新的bean实例,类似于new. Spring

  • Struts中的Action 单例与多例详解

     Struts中的Action 单例与多例详解 struts2中action是多例的,即每次访问网络地址的时候都会产生一个action public class pr_action { public pr_action(){ System.out.println("创建action成功!!!"); } public void execute(){ } } 运行代码可以看到,每次访问该网络地址都会在控制台输出一次!!! 如果是单例的话,若出现两个用户都修改一个对象的属性值,则会因为用户修

  • 关于Java Spring三级缓存和循环依赖的深入理解

    目录 一.什么是循环依赖?什么是三级缓存? 二.三级缓存如何解决循环依赖? 三.使用二级缓存能不能解决循环依赖? 一.什么是循环依赖?什么是三级缓存? [什么是循环依赖]什么是循环依赖很好理解,当我们代码中出现,形如BeanA类中依赖注入BeanB类,BeanB类依赖注入A类时,在IOC过程中creaBean实例化A之后,发现并不能直接initbeanA对象,需要注入B对象,发现对象池里还没有B对象.通过构建函数创建B对象的实例化.又因B对象需要注入A对象,发现对象池里还没有A对象,就会套娃.

随机推荐