【转】Spring Bean单例与线程安全
一、Spring单例模式及线程安全
Spring框架中的Bean,或者说组件,获取实例的时候都是默认单例模式,这是在多线程开发的时候需要尤其注意的地方。
单例模式的意思是只有一个实例,例如在Spring容器中某一个类只有一个实例,而且自行实例化后并项整个系统提供这个实例,这个类称为单例类。
当多个用户同时请求一个服务时,容器会给每一个请求分配一个线程,这时多个线程会并发执行该请求对应的业务逻辑(成员方法),此时就要注意了,如果该处理逻辑中有对单例状态的修改(体现为该单例的成员属性),则必须考虑线程同步问题。
同步机制的比较:
ThreadLocal和线程同步机制相比有什么优势呢?他们都是为了解决多线程中相同变量的访问冲突问题。
ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。 或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。 线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
1) 常量始终是线程安全的,因为只存在读操作。
2)每次调用方法前都新建一个实例是线程安全的,因为不会访问共享的资源。
3)局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部变量,它不是共享的资源。局部变量包括方法的参数变量和方法内变量。
有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象 ,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。
无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象 .不能保存数据,是不变类,是线程安全的。
有状态对象:
无状态的Bean适合用不变模式,技术就是单例模式,这样可以共享实例,提高性能。有状态的Bean,多线程环境下不安全,那么适合用Prototype原型模式。Prototype: 每次对bean的请求都会创建一个新的bean实例。
Struts2默认的实现是Prototype模式。也就是每个请求都新生成一个Action实例,所以不存在线程安全问题。需要注意的是,如果由Spring管理action的生命周期, scope要配成prototype作用域
二、线程安全案例
SimpleDateFormat(下面简称sdf)类内部有一个Calendar对象引用,它用来储存和这个sdf相关的日期信息,例如sdf.parse(dateStr), sdf.format(date) 诸如此类的方法参数传入的日期相关String, Date等等, 都是交友Calendar引用来储存的.这样就会导致一个问题,如果你的sdf是个static的, 那么多个thread 之间就会共享这个sdf, 同时也是共享这个Calendar引用,非线程安全的。
这个问题背后隐藏着一个更为重要的问题--无状态:无状态方法的好处之一,就是它在各种环境下,都可以安全的调用。衡量一个方法是否是有状态的,就看它是否改动了其它的东西,比如全局变量,比如实例的字段。format方法在运行过程中改动了SimpleDateFormat的calendar字段,所以,它是有状态的。
这也同时提醒我们在开发和设计系统的时候注意下一下三点:
1.自己写公用类的时候,要对多线程调用情况下的后果在注释里进行明确说明
2.对线程环境下,对每一个共享的可变变量都要注意其线程安全性
3.我们的类和方法在做设计的时候,要尽量设计成无状态的
解决方法:
1.使用synchronized关键字进行数据同步,或者使用ThreadLocal保证线程安全
2.不适用JDK自带的时间格式化类,使用其他类库的
- 使用Apache commons里的FastDateFormat,宣城是既快有线程安全的SimpleDateFormat,可惜他只能对日期进行format,不能对日期串进行解析
- 使用Joda-Time类库来处理时间相关问题,该种对时间的处理方式比较完美,建议使用。
原文链接:https://www.cnblogs.com/redcool/p/6398760.html
【转】Spring Bean单例与线程安全的更多相关文章
- Spring Bean单例与线程安全
一.Spring单例模式及线程安全 Spring框架中的Bean,或者说组件,获取实例的时候都是默认单例模式,这是在多线程开发的时候需要尤其注意的地方. 单例模式的意思是只有一个实例,例如在Sprin ...
- Spring Controller单例与线程安全那些事儿
目录 单例(siingleton)作用域 原型(Prototype)作用域 多个HTTP请求在Spring控制器内部串行还是并行执行方法? 实现单例模式并模拟大量并发请求,验证线程安全 附录:Spri ...
- spring bean单例注入与用单例模式通过class.getinstance()区别?
1.action的某个方法中,用以下代码获得redis单例实例 RedisDelegate redisDelegate = RedisDelegate.getInstance(); redisDele ...
- Spring 获取单例流程(三)
读完这篇文章你将会收获到 Spring 何时将 bean 加入到第三级缓存和第一级缓存中 Spring 何时回调各种 Aware 接口.BeanPostProcessor .InitializingB ...
- Spring 获取单例流程(二)
读完这篇文章你将会收获到 Spring 中 prototype 类型的 bean 如何做循环依赖检测 Spring 中 singleton 类型的 bean 如何做循环依赖检测 前言 继上一篇文章 S ...
- Spring单例与线程安全小结
一.Spring单例模式与线程安全 Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例模式,这是在多线程开发的时候要尤其注意的地方. 单例模式的意思就是只有一个实例.单例模式确 ...
- spring创建单例bean
(使用的spring版本是3.2.10) 在xml文件中配置一个普通的bean,默认使用单例,创建该bean的调用栈如下: ClassPathXmlApplicationContext //Class ...
- Spring的单例实现原理-登记式单例
单例模式有饿汉模式.懒汉模式.静态内部类.枚举等方式实现,但由于以上模式的构造方法是私有的,不可继承,Spring为实现单例类可继承,使用的是单例注册表的方式(登记式单例). 什么是单例注册表呢, 登 ...
- Spring对单例的底层实现,单例注册表
Spring框架对单例的支持是采用单例注册表的方式进行实现的,源码如下: public abstract class AbstractBeanFactory implements Configurab ...
随机推荐
- 初识React-Redux之粗暴理解入门
权当暂记 日后再行补充完善,若有阅读者,请翻到下文黄色标题'从这里开始'起阅读. Rudex在我看来最本质做的事情就是将所有的State属性统一存储(一个属性就是一个注册到store的Reducer) ...
- 团队工作准则&贡献分配规则
团队工作准则&贡献分配规则 NewTeam 2017/10/24 v1.0 工作准则及内容 全体成员 所有成员在接受任务时应结合自身情况考虑,如果认为任务内容或时间有不合理之处应当立即提出修改 ...
- 百度地图Marker优化方案
简介 在使用百度地图的时候,我们需要在地图上增加标注Marker来展示设置信息.随着用户需要不断增多,加载更多的Marker标注信息成为了一种奢望.然而通过自己技术的提升,归结出来了一下方案. 引入百 ...
- 身为运维的你,怎么掌握python才不会失业
以前,我们都说Python是运维工程师的未来:现在,为什么大家都说不会Python的运维都将失业?运维必须懂开发,特别是python开发,已经形成大家的共识,不懂开发的运维,路会越走越窄. 而现在的情 ...
- 使用.net core在Ubuntu构建一个TCP服务器
介绍和背景 TCP编程是网络编程领域最有趣的部分之一.在Ubuntu环境中,我喜欢使用.NET Core进行TCP编程,并使用本机Ubuntu脚本与TCP服务器进行通信.以前,我在.NET框架本身写了 ...
- SAXParserFactory
Defines a factory API that enables applications to configure and obtain a SAX based parser to parse ...
- typescript入门基础
1.typescript介绍 微软开发的一门编程语言,javascript的一个超集,遵循最新的ES6脚本语言规范(2015年发布),它扩展了Javascript的语法,任何已经写好的javascri ...
- java 之 代理模式(大话设计模式)
java代理模式顾名思义,就类似于大学,我想和冰可乐,可是我又在玩游戏,于是我让我的室友帮我把可乐带回来,简单的来说我的室友就是代理,而买可乐就是需要做的行为.这是笔者理解的代理模式 大话设计模式-类 ...
- win10环境下tensorflow-gpu安装
踩了很多坑,浪费了一下午时间,在此记录一下. pip install tensorflow-gpu 然后下载安装cuda8.0 https://developer.nvidia.com/cuda-do ...
- C# 中枚举的一点研究(跳过一些net坑的研究而已)
之前一直使用Enum.Parse()将字符串转为枚举,没有深究,后面发现一个问题后对下面的Enum有了一个初步研究(.net 4.0).看下面代码. (留意,枚举类型是值类型,其值不能为Null,所以 ...