首页 > 其他分享 >Spring单例的解决方案

Spring单例的解决方案

时间:2023-07-08 23:32:31浏览次数:41  
标签:变量 Spring bean ThreadLocal 线程 单例 解决方案 多线程

1 spring单例 V.S 设计模式的单例

  • 设计模式单例,在整个应用中只有一个实例
  • spring单例,在一个IoC容器中只有一个实例
    Spring框架对单例的支持是采用单例注册表

spring中的单例也不影响应用并发访问。大多数时候客户端都在访问我们应用中的业务对象,为减少并发控制,不应在业务对象中设置那些容易造成出错的成员变量

1.1 成员变量的解决方式

  1. 方法的参数,局部变量(相当于new)
  2. threadlocal、设置bean scope=prototype

2 Spring并发问题

一般无状态Bean才可在多线程环境共享,Spring Bean默认singleton作用域。

有状态bean呢?

2.1 ThreadLocal

Spring对如下的:

  • RequestContextHolder
  • TransactionSynchronizationManager
  • LocaleContextHolder
  • ...

非线程安全状态Bean采用ThreadLocal,让它们也成为线程安全的状态。

用有状态bean,也可使用

2.2 prototype模式

每次注入时,就重建一个bean,在多线程中互不影响。

所有的业务对象中的成员变量

如:

  • Dao中的xxxDao
  • controller中的xxxService

都会被多线程共享,这些对象不会出现同步问题吗?如造成DB插入,更新异常?

实体bean在多线程中的解决方案

如下流程,这些对象都是单例,这些单例对象在处理我们传递到后台的实体bean时不会出问题吗?

传递传递传递客户端controllerserviceDao

因为实体bean不是单例的,他们并没有交给Spring管理!而是每次我们都手动New出来的,如:

BigObject bo = new BigObject()

所以即使那些处理我们提交数据的业务处理类是被多线程共享,但他们处理的数据并不共享,数据是每个线程都有自己的一份,所以数据也不会出现线程安全问题。

实体bean在多线程中的处理

  • 对实体bean一般通过方法参数的的形式传递(参数是局部变量),所以多线程间不会有影响
  • 有的地方对有状态的bean直接使用prototype
  • 对使用bean的地方,可通过new创建

但如下这些对象都是单例:

  • 在Dao中的xxxDao
  • controller中的xxxService

就不会出现线程同步问题。这些对象虽被多线程并发访问,可我们访问的是他们里面的方法,而这些类里面通常不会有成员变量。所以出问题的是系统里面的业务对象,务必注意这些业务对象里,禁止持有独立的成员变量,否则会出错。

2.3 案例

所以我们在应用中的业务对象如下,该应用虽有成员变量,但不会出现线程安全问题。

2.3.1 controller中的成员变量

Spring单例的解决方案_多线程

  • private TestPaperService papersService之所以会成为成员变量,目的是注入,将其实例化进而访问里面的方法!
  • private static final int List = 0; final的不会被改变!

2.3.2 service里的成员变量

Spring单例的解决方案_多线程_02

service里的private IbatisEntityDao ibatisEntityDao;是框架本身的,线程同步问题已解决。

3 ThreadLocal使用

要给线程初始化一个特殊值时,需要自己实现ThreadLocal的子类并重写该方法,通常使用一个内部匿名类对ThreadLocal进行子类化,EasyDBO中创建jdbc连接上下文就是这样:

Spring单例的解决方案_成员变量_03

简单实现

ThreadLocal V.S synchronized

为保证多个线程对共享变量的安全访问,通常会使用synchronized保证同时只有一个线程对共享变量进行操作。但有些情况下,synchronized不能保证多线程对共享变量的正确读写。

如类有个类变量,该类变量会被多个类方法读写,当多线程操作该类的实例对象时,若线程对类变量有读、写就会发生类变量读写错误,即便在类方法前加synchronized也无效,因为同一线程在两次调用方法之间时,锁是被释放的,这时其它线程可访问对象的类方法,读取或修改类变量。这时,可将类变量放到ThreadLocal中,使变量在每个线程中都有独立拷贝,完全避免一个线程读取变量时而被另一线程修改。

4 总结

若一个对象要被多个线程访问,而该对象存在类变量被不同类方法读写,为获得线程安全,可用ThreadLocal替代类变量。

ThreadLocal和线程同步机制相比有什么优势呢?

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。

同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要分析:

  • 什么时候对变量进行读写
  • 什么时候需要锁定某个对象
  • 什么时候释放对象锁等繁杂的问题

而ThreadLocal为每个线程提供一个独立变量副本,隔离多线程对数据的访问冲突。ThreadLocal采用“以空间换时间”。

Spring使用ThreadLocal解决线程安全问题

一般只有无状态Bean才能在多线程下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,让它们也成为线程安全的状态,有状态Bean就能在多线程中共享了。

一般Web应用划分为展现层、服务层和持久层三个层次,从接收请求到返回响应所经过的所有程序调用都同属于一个线程。这就能根据需要,将一些非线程安全的变量以ThreadLocal存放,在同一次请求响应的调用线程中,所有关联的对象引用到的都是同一个变量。

很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高并发性。

参考

  • 浅谈Spring声明式事务管理ThreadLocal和JDKPro

标签:变量,Spring,bean,ThreadLocal,线程,单例,解决方案,多线程
From: https://blog.51cto.com/JavaEdge/6663947

相关文章

  • springcloud - 通过消息总线bus进行刷新
    修改3344服务pom文件 <!--添加消息总线RabbitMQ支持--> <dependency>   <groupId>org.springframework.cloud</groupId>   <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>yaml文件 #rabbitmq相关配置 spring: ......
  • springcloud -config配置中心 整合github 或者gitee 单个刷新配置
    配置中心,通过从开源仓库上拉去配置,而不是在本地修改服务端配置cloud-config-center-3344     <dependency>       <groupId>org.springframework.cloud</groupId>       <artifactId>spring-cloud-config-server</artifactId>   ......
  • SpringBoot 集成异步线程调用
    步骤:1、在自动审核的方法上加上@Async注解(标明要异步调用)2、在文章发布成功后调用审核的方法3、在自媒体引导类中使用@EnableAsync注解开启异步调用 ......
  • 通用权限系统-Spring-Boot-Starter
    Spring-Boot-Starter自定义Starter案例一:读取application.yml中的参数1、创建1、创建maven工程hello-spring-boot-starter2、pom中添加依赖<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:......
  • 数据权限解决方案
    一、表结构设计  二、实现思路 1.系统启动时将字典数据加载到redis作为可选常量池,以及mapper.xml、dao、数据规则信息加载到redis 2.用访问时通过springmvc拦截器对用户进行拦截获取token然后通过RSA解密获取用户信息,将用户信息,以及请求参数加入本地线程 3.mybatis-......
  • Web开发|SpringBoot-Bean
    起因:经常在Config文件里看见Bean的存在,所以开始探究Bean的概念还使用方法。原文来自:https://gustavopeiretti.com/spring-boot-bean-annotation/#:~:text=What%20is%20%40Configuration%20in%20Spring,other%20parts%20of%20the%20application. 在SpringBoot中,@Bean是一个方......
  • spring-boot集成mybatis-plus
    spring-boot集成mybatis-plus目录spring-boot集成mybatis-plus依赖配置application.properties文件启动类添加@Mapper注解编码实体类Mapper类Service类测试@Test测试测试结果依赖 <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter<......
  • Spring中的Controller和Service是线程安全的吗?我有点懵
    结论:不是线程安全的Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean去研究。Spring的bean作用域(scope)类型singleton:单例,默认作用域。prototype:原型,每次创......
  • spring
    SpringSpring简介Spring是一个开源的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应特点:Spring是一个开源免费的框架,容器;Spring是一个轻量级的框架,非入侵式的;控制反转IoC,面向切面编程AOP;对事务的支持,对框架的支持......
  • 智慧零售解决方案(新零售线上线下一体化)
    一、解决方案概述基于SG500工业网关的智慧零售解决方案,通过物联网、大数据和人工智能等先进技术,实现零售场景的数字化、网络化和智能化。该解决方案将各类传感器、监控设备、收银系统、会员管理系统等与SG500工业网关相连接,实现数据的实时采集、传输、分析和处理,为零售商......