Spring 中线程的安全问题

首先,介绍spring容器中的Bean 作用域有如下5种:

  1. singleton 单例模式
  2. prototype 原型模式
  3. request (WebApplicationContext环境)
  4. session (WebApplicationContext环境)
  5. global-session (WebApplicationContext环境)

singleton
在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例。spring默认是singleton。
prototype
每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例,相当于new 对象()。
request
对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效。
session
对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效。
global-session
每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效。

SpringMVC多线程下
一 。使用singleton:

在一般情况下,只有无状态的Bean(Bean里面没有状态属性)才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。

解释说明一下:(有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象 ,可以保存数据,是非线程安全的。无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象 .不能保存数据,是不变类,是线程安全的。
无状态的Bean适合用不变模式,技术就是单例模式,这样可以共享实例,提高性能。)

如何保证变量安全性
恶劣情况下,如果是有状态的Bean使用singleton作用域,如果该Bean里面的变量不采取处理,就有可能出现数据错乱的情况。所以这时需要用到ThreadLocal,它会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal(仅仅是变量,因为线程同步的问题就是成员变量的互斥访问出问题)。就相当对把每个线程的名字和变量值以键值对的形式存进Map,当对应的线程访问时,以线程名字取出自己的值,如果没有值则创建自己对应的副本。ThreadLocal采用了“空间换时间”的方式。

ThreadLocal 使用范例:

ThreadLocal<Long>startTime = newThreadLocal<Long>();  定义一个ThreadLocal 变量
startTime.set(System.currentTimeMillis());   写入值
startTime.get();  读取值

如何保证对象的安全性
如果是Bean里面有共用的对象,而且对象里面的方法对数值操作。如下代码:
Controllern层

@RequestMapping("/user") 
@Controller 
Class UserController {
   
	
	@Resource 
	UserService userService; 
	
	@RequestMapping("/add") 
	public void testA(User user){
   
		userService.add(user); 
	} 
	
	@RequestMapping("/get") 
	public void testA(int id){
   
		userService.get(id); 	
	} 
}

Service层:

@Service("userService") 
Class UserService{
    
	
	public static Map<Integer,User> usersCache = new HashMap<String,User>(); 
	
	public void add(User user){
    
		usersCache.put(user.getId(),user); 
	} 
	
	public void get(int id){
    
		usersCache.get(id); 
	} 
}

这个时候如果Controller、Dao、Service 都是singleton单例模式的话,多个线程同时调用add方法时,有可能会发生用户对象被覆盖,再用get(int id)方法的时候有可能取到的对象不一致。

1)这个时候可以使用 Collections 工具类,它里面有个synchronizedMap方法可以同步Map对象。更改代码如下:

static Map<Integer, Users> usersCache = Collections.synchronizedMap(new HashMap<Integer, Users>()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值