单例模式--来点新写法
Posted 微服务与大数据笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式--来点新写法相关的知识,希望对你有一定的参考价值。
常见到的饿汉模式单例,懒汉模式单例,区别就在于实例化对象,前者是类一加载的时候就初始化对象,后者是类被调用的时候,才初始化对象。
但今天要说的是,在并发情况下,如何保证并发安全的前提下,提高并发效率的使用。
对着代码分析:
常见高并发情境下的单例模式实现:
public class UserService {
private static volatile UserService instance = null;
private UserService(){}
public static UserService getInstance(){
if(instance == null){
synchronized (UserService.class){
if(instance == null){
return new UserService();
}
}
}
return instance;
}
public String getUserInfo(){
return "tangyuan";
}
}
# 这里采用懒汉模式,即第3行,构建的空对象。当对象被调用的时候才 new 对象。
第5行,构造函数私有化。这样在其他地方就不能直接 new UserService()对象,必须通过getInstance() 方法,获取对象。
第3行,先定义一个私有空对象,注意这里使用 volatile 修饰了instance,为了保证并发时,instance对象在主存中的可视性,保证先行发生关系(happens-before relationship),对于instance,所有的写(write)都将先行发生于读(read),注意,volatile不能保证原子性。
第8行,第一重校验,instance是否为null,并发时,可能会已被实例化,则不需要进入synchronized 修饰的代码块中,实例化。
第10行,第二重校验:并发时,可能可能A请求刚刚进入第10行,但实际上B请求先行释放锁,已new UserService() 。
上述写法很麻烦,还需要考虑各种锁的问题,实际上我们可以使用枚举的方式,代码简单,有效。如下:
public enum EasySingleton {
INSTANCE;
public String getUserInfo(){
return "tangyuan";
}
}
其实,1行代码就解决问题了。
有同学会问,我怎么调用它呢。
如下:
public class Test {
public static void main(String[] args) {
EasySingleton easySingleton = INSTANCE;
System.out.println(easySingleton.getUserInfo());
}
}
我再推荐另一种写法,这个没查到相关资料,但是在和同事讨论下,认为可行的一种方案,如果有同学认为有歧义,还请指正。
实际上,现在大部分基于Java实现的产品,都会使用Spring 去管理bean。 其Bean 的生命周期,也由Spring 的容器进行管理。 Bean定义中,默认其bean 是单例的。所以,直接如下写法,在需要调用该Bean的时候,直接注入即可。
优点在于:1.不用我们自己维护单例 的生命周期及其实现。 2.解耦和,单例模式最大的弊端,我认为其扩展性太弱,耦合性太强。所有使用的地方,都需要调用getInstance()方法。
@Component
public class SpringSingleTone {
public String getUserInfo(){
return "tangyuan";
}
}
如有错误,欢迎指正!
以上是关于单例模式--来点新写法的主要内容,如果未能解决你的问题,请参考以下文章