单例 Bean 的线程安全问题
最近面试遇到一个问题:单例 Bean 的线程安全问题怎么解决的。
之前了解但是没有深究它的解决方法。大部分时候我们并没有在项目中使用多线程,所以很少有人会关注这个问题。
大部分 Bean 实际都是无状态(没有实例变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。
因为Spring 默认情况下是单例的(singleton)。所有我们会遇见多个线程操作同一个对象的时候是存在资源竞争的问题。
常见的有两种解决办法:
在 Bean 中尽量避免定义可变的成员变量。
在类中定义一个
ThreadLocal
成员变量,将需要的可变成员变量保存在ThreadLocal
中(推荐的一种方式)。 在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
而
ThreadLocal
则从另一个角度来解决多线程的并发访问。ThreadLocal
会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。不同线程只操作自己线程的副本变量。ThreadLocal
提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal
。ThreadLocal
代码举例private static ThreadLocal<Integer> content=new ThreadLocal<Integer>(){ protected Integer initalValue(){
return (int)(Math.random()*10+100);
} }; private static ThreadLocal<Integer> test=new ThreadLocal<Integer>(){ protected String initalValue(){
return "单例模式是不安全的" +(int)(Math.random()*10+100);
}
};
public Object get(){
System.out.println(content.get());
System.out.println(test.get());
System.out.println();
return test.get();
}
将有状态的bean的作用域由“singleton”改为“prototype”。( 如注解 : @Scope("prototype") );
使用线程同步,加关键字synchronized。对多线程性能有一定影响(此方法没试验过 慎用!);
最新文章
- SSTable 介绍(一)
- Eclipse设置和必装插件
- Deep Learning in NLP (一)词向量和语言模型
- Gradle简介
- Intellij Idea 15 生成serialVersionUID的方法
- delphi 查找对话框
- 全面学习cookies
- Base64 encode/decode large file
- awk基础 [马哥视频]
- 不使用ASP.NET服务器端控件(包括form表单不加runat=";server";)来触发.cs里的事件(方法),(适用于有代码洁癖者)。
- 如何在程序中动态设置墙纸(使用IActiveDesktop接口)
- IM应用中的优化
- 仅以一个前端开发人员的角度看微信小程序
- mysql 查询select语句汇总
- Java基础中一些容易被忽视的语法小细节总结
- 微信支付之01------获取订单微信支付二维码的接口------Java实现
- 微信小程序--家庭记账本开发--04
- hihocoder #1236 Scores (15北京赛区网络赛J) (五维偏序,强制在线,bitset+分块)
- Latex 算法过长 分页显示方法
- php 访问错误日志