Spring Bean单例与线程安全
一、Spring单例模式及线程安全
Spring框架中的Bean,或者说组件,获取实例的时候都是默认单例模式,这是在多线程开发的时候需要尤其注意的地方。
单例模式的意思是只有一个实例,例如在Spring容器中某一个类只有一个实例,而且自行实例化后并项整个系统提供这个实例,这个类称为单例类。
当多个用户同时请求一个服务时,容器会给每一个请求分配一个线程,这时多个线程会并发执行该请求对应的业务逻辑(成员方法),此时就要注意了,如果该处理逻辑中有对单例状态的修改(体现为该单例的成员属性),则必须考虑线程同步问题。
同步机制的比较:
ThreadLocal和线程同步机制相比有什么优势呢?他们都是为了解决多线程中相同变量的访问冲突问题。
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。 或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。 线程安全问题都是由全局变量及静态变量引起的。
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类库来处理时间相关问题,该种对时间的处理方式比较完美,建议使用。
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 ...
随机推荐
- FlexPaper_1.2.1.swc——Flex在线显示PDF文档(使用FlexPaper)感悟
http://www.cnblogs.com/wuhenke/archive/2010/03/16/1686885.html 想想自己先前搞PDF转SWF,然后在线浏览功能时,实在是费了不少精力.后来 ...
- springboot+mybatis项目自动生成
springboot_data_access_demo基于rapid,根据自定义模版生成的基于mybatis+mysql的数据库访问示例项目.简单配置数据库信息,配置不同的生成策略生成可以直接运行访问 ...
- Web漏洞挖掘之网络信息探测
我们在搜集目标系统信息的时候主要需要搜集的是:目标服务器系统信息(IP,服务器所用系统等):目标网站子域名:目标网站(服务器)的开放端口:目标域名信息.目标网站内容管理系统(CMS)等. 一.子域名搜 ...
- [转] sql server 跨数据库调用存储过程
A库存储过程: create PROCEDURE [dbo].[spAAAForTest] ( ) =null , ) =null ) AS BEGIN select N'A' AS a , N'B' ...
- php环境重启
php-fpm mysql nginx 一个lnmp的服务,主要就是靠这三个来维持的. 重启nginx # /usr/local/nginx/sbin/nginx -s stop # /usr/loc ...
- [原][osgearth]FAQ
参考:http://docs.osgearth.org/en/latest/faq.html Common Usage How do I place a 3D model on the map? Th ...
- 【转】IntelliJ IDEA的光芒会盖过Eclipse吗
作为一个资深的Eclipse用户,我想对IntelliJ IDEA做一个更为严谨的审视.JetBrains的工作人员非常的友善,并为Podcastpedia.org和Codingpedia.org这两 ...
- Rails 5 Test Prescriptions(everday Rspectest作者推荐) 目录 1-3章
总文档连接: RSpec.info/documentation/ 如何使用TDD 和 自动化测试来建立一个Rails app. TDD让你用测试来探索代码的设计.你将学习可利用的工具,并学习用什么工具 ...
- bzoj 3730 震波 (动态点分治)
大意: 给定n节点树, 每个节点有权值, 边权全为1. 给定m个操作: 操作1: (0,x,k) 表示询问到节点x距离不超过k的节点权值和 操作2: (1,x,y) 表示将节点x的权值修改为y 对于所 ...
- 在python中引用jar包
在本文中,首先创建一个maven项目,然后打包成jar包,在python中调用jar包,执行java类方法. 1.在eclipse中创建maven项目 我这里创建一个普通java项目,择选择 “mav ...