文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java中Spring的单例模式使用

2024-04-02 19:55

关注

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

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

2.成员变量的解决方式

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

3.Spring并发问题

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

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

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

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

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

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

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

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

  1. 在Dao中的xxxDao
  2. controller中的xxxService

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

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

controller中的成员变量List和paperService:

service里的成员变量ibatisEntityDao:

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

5.spring无状态的支持

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

6.spring有状态的支持

spring如何实现那些个有状态bean,如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder]的线程安全,即使用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分别设置:

使用时先创建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的单例模式使用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯