Java中Spring的单例模式使用

目录
  • 1.spring单例 V.S 设计模式的单例
  • 2.成员变量的解决方式
  • 3.Spring并发问题
  • 4.对实体bean在多线程中的处理
  • 5.spring无状态的支持
  • 6.spring有状态的支持
  • 7.ThreadLocal
  • 8.ThreadLocal使用
  • 9.ThreadLocal V.S synchronized
  • 10.Spring使用ThreadLocal解决线程安全问题

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

  • 设计模式单例,在整个应用中只有一个实例
  • spring单例,在一个IoC容器中只有一个实例

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

2.成员变量的解决方式

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

Spring Bean Scope 有状态的Bean与无状态的Bean

3.Spring并发问题

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

那有状态bean呢?Spring对一些如

  • RequestContextHolder
  • TransactionSynchronizationManager
  • LocaleContextHolder

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

如用有状态bean,也可使用prototype模式,每次在注入时,就重新创建一个bean,在多线程中互不影响。

Eic-server所有的业务对象中的成员变量如:

  • Dao中的xxxDao
  • controller中的xxxService

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

实体bean,从客户端传递到后台controller=》service=>Dao流程中,他们这些对象都是单例的,那这些单例对象在处理我们的传递到后台的实体bean不会出问题吗?(实体bean在多线程中的解决方案)
因为实体bean不是单例的,他们并没有交给Spring管理!每次我们都手动的New出来的,如BigObject bo = new BigObject(),所以即使是那些处理我们提交数据的业务处理类是被多线程共享,但他们处理的数据并不共享,数据是每个线程都有自己的一份,所以在数据方面不会出现线程安全问题。

4.对实体bean在多线程中的处理

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

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

所以我们在应用中的业务对象如下:

controller中的成员变量List和paperService:

service里的成员变量ibatisEntityDao:

虽然这个应用有成员变量,但不会出现线程安全问题:

  • controller里的成员变量private TestPaperService papersService 之所以会成为成员变量,我们的目的是注入,将其实例化进而访问里面的方法
  • private static final int List = 0;是final的不会被改变
  • service里面的private IbatisEntityDao ibatisEntityDao;是框架本身的,线程同步问题已解决

5.spring无状态的支持

Spring框架对单例的支持是采用单例注册表。

6.spring有状态的支持

spring如何实现那些个有状态bean,如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder]的线程安全,即使用ThreadLocal实现的

  • Spring中ThreadLocal的使用

7.ThreadLocal

当使用ThreadLocal维护变量(仅是变量,因为线程同步问题就是成员变量的互斥访问出问题)时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都可独立改变自己的副本,而不会影响其它线程所对应副本。

从线程角度看,就好像每一个线程都完全拥有该变量,这其实就将共享变相为人手一份。虽使用ThreadLocal带来更多内存开销,但这点开销还微不足道。因为保存在ThreadLocal中的对象,通常较小。

initialValue(),protected的方法,为子类重写而实现。该方法返回当前线程在该线程局部变量的初始值,是个延迟调用方法,在一个线程第1次调用get()或set(Object)时才执行且仅执行1次。

8.ThreadLocal使用

要给线程初始化一个特殊值时,需要自己实现ThreadLocal的子类并重写该方法,通常使用一个内部匿名类对ThreadLocal进行子类化,

EasyDBO中创建jdbc连接上下文就是这样做的:

简单实现版本:

9.ThreadLocal V.S synchronized

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

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

多线程访问对于类变量和ThreadLocal变量的影响,QuerySvc分别设置:

  • 类变量sql
  • ThreadLocal变量

使用时先创建QuerySvc的一个实例对象,然后产生多个线程,分别设置不同sql实例对象,再调用execute,读取sql的值,看是否是set方法中写入的值。这类似web应用中多个请求线程携带不同查询条件对一个servlet实例的访问,然后servlet调用业务对象,并传入不同查询条件,最后要保证每个请求得到的结果是对应的查询条件的结果。

使用QuerySvc的工作线程如下:

运行线程:

先创建一个QuerySvc实例对象,然后创建若干线程来调用QuerySvc的set和execute方法,每个线程传入的sql都不一样,sql变量中值不能保证在execute中值和set设置的值一样,在web应用中就表现为一个用户查询的结果不是自己的查询条件返回的结果,而是另一个用户查询条件的结果。

而ThreadLocal中的值总是和set中设置的值一样,这样通过使用ThreadLocal获得了线程安全性。

小结:

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

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

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

同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。

这时该变量是多个线程共享的,使用同步机制要分析:

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

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

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

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

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

ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。

到此这篇关于Java中Spring的单例模式使用的文章就介绍到这了,更多相关Spring的单例模式使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java 实例解析单例模式

    目录 单例模式的介绍 优点 缺点 Synchronized Synchronized示例 Synchronized与非Synchronized Singleton 第一个示例 第二个示例 第三个示例 第四个示例 第五个示例 单例模式的介绍 单例对象(Singleton)是一种常用的设计模式.在实际使用中,单例对象能保证在一个JVM中,该对象只存在一个实例存在. 优点 1.减少系统开销,提高系统性能 2.省去了new操作符,降低了系统内存的使用频率,减轻GC压力 3.避免对共享资源的多重占用 缺点

  • Java 单例模式详细解释

    目录 饿汉式 懒汉式 懒汉式(加锁synchronized) 懒汉式(部分加锁synchronized) 懒汉式(DCL) 懒汉式(DCL)最终版 静态内部类 总结 饿汉式 /** * 饿汉式 * 类加载到内存后,就是实例化一个单例,JVM保证线程安全 * 简单使用:推荐使用 * 唯一缺点:不管用与不用,类加载时就会完成实例化 */ public class Demo01 { //开始先新建一个对象 private static final Demo01 INSTANCE = new Demo0

  • Java单例模式的深入了解

    目录 一.设计模式概览 1.1.软件设计模式的概念 1.2.软件设计模式的基本要素 1.3.GoF 的 23 种设计模式的分类和功能 1.4.软件设计的七大原则 二.单利模式 1.1.单例模式的相关定义 1.2.单利模式的结构 2.1单利模式的实现方式一:懒汉式 2.2单利模式的实现方式一:饿汉式 总结 一.设计模式概览 1.1.软件设计模式的概念 软件设计模式(Software Design Pattern),又称设计模式,是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.它

  • Java设计模式之单例模式示例详解

    目录 0.概述 1.饿汉式 1.1 饿汉式单例实现 1.2 破坏单例的几种情况 1.3 预防单例的破坏 2.枚举饿汉式 2.1 枚举单例实现 2.2 破坏单例 3.懒汉式 4.双检锁懒汉式 5.内部类懒汉式 6.JDK中单例的体现 0.概述 为什么要使用单例模式? 在我们的系统中,有一些对象其实我们只需要一个,比如说:线程池.缓存.对话框.注册表.日志对象.充当打印机.显卡等设备驱动程序的对象.事实上,这一类对象只能有一个实例,如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常.

  • 深入理解Java设计模式之单例模式

    目录 一.什么是单例模式 二.单例模式的应用场景 三.单例模式的优缺点 四.单例模式的实现 1.饿汉式 2.懒汉式 3.双重加锁机制 4.静态初始化 五.总结 一.什么是单例模式 单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在. 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为.比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息.这种方式简

  • Java中Spring的单例模式使用

    目录 1.spring单例 V.S 设计模式的单例 2.成员变量的解决方式 3.Spring并发问题 4.对实体bean在多线程中的处理 5.spring无状态的支持 6.spring有状态的支持 7.ThreadLocal 8.ThreadLocal使用 9.ThreadLocal V.S synchronized 10.Spring使用ThreadLocal解决线程安全问题 1.spring单例 V.S 设计模式的单例 设计模式单例,在整个应用中只有一个实例 spring单例,在一个IoC容

  • Java中Spring获取bean方法小结

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,如何在程序中获取Spring配置的bean呢? Bean工厂(com.springframework.beans.factory.BeanFactory)是Spring框架最核心的接口,它提供了高级IoC的配置机制.BeanFactory使管理不同类型的Java对象成为可能,应用上下文(com.springframework.context.ApplicationContext)建立在BeanFactory基础之上,提供

  • 详解java 中Spring jsonp 跨域请求的实例

    详解java 中Spring jsonp 跨域请求的实例 jsonp介绍 JSONP(JSON with Padding)是JSON的一种"使用模式",可用于解决主流浏览器的跨域数据访问的问题.由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外.利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSO

  • java中Spring Security的实例详解

    java中Spring Security的实例详解 spring security是一个多方面的安全认证框架,提供了基于JavaEE规范的完整的安全认证解决方案.并且可以很好与目前主流的认证框架(如CAS,中央授权系统)集成.使用spring security的初衷是解决不同用户登录不同应用程序的权限问题,说到权限包括两部分:认证和授权.认证是告诉系统你是谁,授权是指知道你是谁后是否有权限访问系统(授权后一般会在服务端创建一个token,之后用这个token进行后续行为的交互). spring

  • java 中Spring task定时任务的深入理解

    java 中Spring task定时任务的深入理解 在工作中有用到spring task作为定时任务的处理,spring通过接口TaskExecutor和TaskScheduler这两个接口的方式为异步定时任务提供了一种抽象.这就意味着spring容许你使用其他的定时任务框架,当然spring自身也提供了一种定时任务的实现:spring task.spring task支持线程池,可以高效处理许多不同的定时任务.同时,spring还支持使用Java自带的Timer定时器和Quartz定时框架.

  • JAVA 中Spring的@Async用法总结

    JAVA 中Spring的@Async用法总结 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3.x之后,就已经内置了@Async来完美解决这个问题,本文将完成介绍@Async的用法. 1.  何为异步调用? 在解释异步调用之前,我们先来看同步调用的定义:同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果. 异步调用则是只是发送了调用的

  • Java中Spring Boot+Socket实现与html页面的长连接实例详解

    Spring Boot+Socket实现与html页面的长连接,客户端给服务器端发消息,服务器给客户端轮询发送消息,附案例源码 功能介绍 客户端给所有在线用户发送消息客户端给指定在线用户发送消息服务器给客户端发送消息(轮询方式) 注意:socket只是实现一些简单的功能,具体的还需根据自身情况,代码稍微改造下 项目搭建 项目结构图 pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xml

  • Java中Spring Boot支付宝扫码支付及支付回调的实现代码

    前言:最近开发支付宝支付功能,总结一下做个分享 官方文档:https://opendocs.alipay.com/apis 支付宝沙箱地址: https://openhome.alipay.com/platform/appDaily.htm?tab=info 支付宝支付流程: 准备工作:获取支付宝沙箱数据(APPID,支付宝网关,RSA2秘,沙箱支付账号等) 集成SpringBoot,使用Java代码发起支付请求 支付宝收到支付请求后,返回HTML代码片段,用于前端展示二维码 扫码支付成功后,支

  • 分析java中全面的单例模式多种实现方式

    一.单例模式的思想 想整理一些 java 并发相关的知识,不知道从哪开始,想起了单例模式中要考虑的线程安全,就从单例模式开始吧.以前写过单例模式,这里再重新汇总补充整理一下,单例模式的多种实现. 单例模式的主要思想是: 将构造方法私有化( 声明为 private ),这样外界不能随意 new 出新的实例对象: 声明一个私有的静态的实例对象,供外界使用: 提供一个公开的方法,让外界获得该类的实例对象 这种说法看上去没错,但也好像不太准确.其实,就算外界能随意 new 出新的实例对象,但只要我们保证

  • Java中Spring技巧之扩展点的应用

    目录 前言: Spring常见扩展点 总结 前言: 最近在看公司项目和中间件的时候,看到一些Spring扩展点的使用,写篇文章学习下,对大家之后看源码都有帮助 首先先介绍下Bean的生命周期: 我们知道Bean的生命周期分为几个主干流程 Bean(单例非懒加载)的实例化阶段 Bean的属性注入阶段 Bean的初始化阶段 Bean的销毁阶段 下面是整个Spring容器的启动流程,可以看到除了上述几个主干流程外,Spring还提供了很多扩展点 下面详细介绍下Spring的常见的扩展点 Spring常

随机推荐