Java单例模式——暂时完美的单例
来源:互联网 发布:学车电销数据 编辑:程序博客网 时间:2024/06/07 17:39
最近在网上找资料研究了下单例模式,结合网上的资料记录下暂时完美的单例:
一、暂时完美单例
public class Singleton { //私有构造方法,防止被实例化 private Singleton(){} //此处使用一个内部类来维护单例 private static class SingletonFactory{ private static Singleton instance = new Singleton(); } //获取实例 public static Singleton getInstance(){ return SingletonFactory.instance; } //如果对象被用于序列化,可以保证对象在序列化前后一致 public Object readResolve(){ return getInstance(); }}
当第一次加载Singleton时并不会初始化instance,只有在第一次调用Singleton的getInstance()方法是才会触发instance的初始化。因此,第一次调用getInstance()方法会导致虚拟机加载SingletonFactory类,这种方式不仅能够确保线程安全,也能够保证单例对象的唯一性,同事也延迟了单例的实例化,所以这是推荐使用的暂时完美的单例模式。
二、使用广泛的单例:Double Check Lock(DCL)单例模式
public class Singleton { //私有构造方法,防止被实例化 private Singleton(){} private static Singleton instance = null; //获取实例 public static Singleton getInstance(){ if(instance == null){ synchronized(){ if(instance == null){ instance = new Singleton(); } } } return instance; } //如果对象被用于序列化,可以保证对象在序列化前后一致 public Object readResolve(){ return getInstance(); }}
DCL单例的亮点在getInstance()上,可以看到getInstance()方法中对instance进行了两次判空:第一层判断主要是为了避免不必要的同步,第二层判断则是为了在null的情况下创建实例。
我们来具体分析下。
假设线程A执行到instance = new Singleton()语句,这里看起来是语句代码,但实际上它并不是一个原子操作,这句代码最终会编译成多条汇编指令,它大致做了3个动作:
a.给Singleton实例分配内存;
b.调用Singleton()的构造函数,初始化成员字段;
c.将instance 对象指向分配的内存空间(instance 此时不为空)。
But……,由于Java编译器允许处理器乱序执行,以及JDK1.5之前JMM(Java Memory Model即Java内存模型)中Cache、寄存器到主内存回写顺序的规定,上面的b和c顺序是无法保证的。也就是说,执行顺序可能是a-b-c,也可能是a-c-b。如果是后者,并且在c执行完b未执行之前, 切换到B线程上,这时候instance 以为已经在A线程内执行过了c,instance 已经是非空了,所以,线程B直接取走instance ,再使用时就会报空,这就是DCL失效问题, 而且这种错误很难以追踪和重现,可能会导致bug长期潜伏在程序中,造成严重后果。
在JDK1.5之后,SUN官方已经注意到这个问题,调整了JVM,具体化了volatile关键字。因此,如果是JDK1.5或者1.5之后的版本,只需要将instance的定义改成private static volatile Singleton instance = null;就可以保证instance 对象每次都是从主内存中读取的,就可以使用DCL的写法来完成单例模式。
网上的资料有的说volatile或多或少会影响到性能,到考虑到程序的正确性,牺牲这点微不足道的性能还是值得的。
DCL方法实现单例模式的优点:既能够在需要时才开始实例化,又能够保证线程安全,且单例对象初始化后调用getInstance()不进行同步锁。
缺点:第一次加载时反应慢,也由于Java内存模型原因偶尔会失败。在高并发的环境下也有一定的缺陷,虽然发生的概率很小。这个问题被称为双重检查锁定(DCL)失效,在《Java并发编程实践》一书的最后讲到了这个问题,并指出这种“优化”是丑陋的,不赞成使用,建议使用例一的单例模式。
- Java单例模式——暂时完美的单例
- java 完美的单例模式
- 完美的单例模式
- 完美的单例模式
- Java 设计模式—单例模式
- java设计模式—单例模式
- java设计模式—单例模式
- java设计模式—单例模式
- Java设计模式—单例模式
- Java设计模式—单例模式
- Java的单例模式
- Java的单例模式
- java的单例模式
- java的单例模式
- Java的单例模式
- Java的单例模式
- java的单例模式
- java的单例模式
- Robomongo连接远程MongoDB数据库
- DonMin-2017-6-2-day07
- 第一课 JSON的简介
- React Native集成到IOS原生项目
- nginx+php显示 502 bad gateway的解决方法
- Java单例模式——暂时完美的单例
- EventBus使用详解(一)——初步使用EventBus
- lintcode(653)Add Operators
- codeforces 472A Design Tutorial: Learn from Math
- Spring(一)概况
- SDOI2013 森林
- 【Android】【Framework】MessageQueue
- 根据OLAMI平台开发的日历Demo
- 正则表达式