Java实现单例模式
来源:互联网 发布:虚拟商品怎么淘宝介入 编辑:程序博客网 时间:2024/04/29 11:59
定义
单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理[1]。(来自wiki)
构建方式
通常我们有两种方式来构建单例。
懒汉方式:指全局的单例实例在第一次被使用时构建。
饿汉方式:指全局的单例实例在类加载时构建。
构建代码
懒汉式(线程不安全)
public class Singleton { private static Singleton INSTANCE = null; private Singleton() { } public static Singleton getInstance() { if (INSTANCE == null) INSTANCE = new Singleton(); return INSTANCE; }}
优点是容易理解,缺点是在多线程下可能会出现两个实例。
懒汉式(线程安全)
public class Singleton { private static Singleton INSTANCE = null; private Singleton() { } public static synchronized Singleton getInstance() { if (INSTANCE == null) INSTANCE = new Singleton(); return INSTANCE; }}
优点是线程安全,缺点是效率低下,每次获取单例实例的时候都需要加锁,而加锁是一个非常耗时的操作,在没有必要的时候我们应该尽量避免。
懒汉式(DCL:双重检验锁)
public class Singleton { private static Singleton INSTANCE = null; private Singleton() { } public static synchronized Singleton getInstance() { if (INSTANCE == null) { synchronized (Singleton.class) { if (INSTANCE == null) { INSTANCE = new Singleton(); } } } return INSTANCE; }}
老外对这种写法的评价是:Clever, but broken
DCL理论上无懈可击,实际上,现实世界并不是这样的。DCL无法保证在单处理器还是多处理器的机器上正常工作。DCL失败的问题不在于JVMs的bug,而是当前Java平台的内存模型。内存模型允许”out-of-order writes”的存在,并且它是DCL失败的罪魁祸首[2]。
out-of-order writes
整个问题的关键就出在 INSTANCE = new Singleton();
这句代码可以分解为下面三步:
mem = allocate(); //为Singleton对象的创建分配空间INSTANCE = mem; //此时的INSTANCE已经不为null,但是它还没有被初始化ctorSingleton(instance); //调用Singleton的构造函数
当执行到第二步时,内存已经分配了,INSTANCE引用也已指向新分配内存,而构造函数却还未执行。在此时,如果另一个线程来check INSTANCE时,会发现该INSTANCE已经不为null了,于是直接越过同步块,返回INSTANCE所引用的构造了一半的实例。这就是导致DCL失败的原因[2]。
网络上面有些文章说可以通过 volatile 关键字修饰INSTANCE使得DCL可以正常工作,但我看国外的文章说 volatile 也会产生其他的问题[2][3]。
饿汉式(static final)
public class Singleton { private final static Singleton INSTANCE = new Singleton(); private Singleton() { } public static Singleton getInstance() { return INSTANCE; }}
静态内部类
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton() { } public static Singleton getInstance() { return SingletonHolder.INSTANCE; }}
由于静态内部类在第一次使用的时候才会被加载,所以它属于懒汉式的,又因为这个实现过程没有加锁,所以在性能上也能达到很好的效果,JVM保证了线程安全。
饿汉式(枚举)
public enum EasySingleton{ INSTANCE;}
参考文献
1.https://zh.wikipedia.org/wiki/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F
2.http://www.ibm.com/developerworks/library/j-dcl/
3.http://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking–clever–but-broken.html
- 单例模式 java 实现
- 单例模式--java实现
- java 实现单例模式
- java实现单例模式
- java 实现单例模式
- Java实现单例模式
- Java 实现单例模式
- java实现单例模式
- java 实现单例模式
- java实现单例模式
- java实现单例模式
- Java实现单例模式
- JAVA实现单例模式
- Java实现单例模式
- java单例模式实现
- 单例模式Java实现
- java 实现单例模式
- java实现单例模式
- XAMPP的
- [0.0]感动 Mr.Snail 作品集
- 年龄几何
- 【动态规划】字符串最小编辑距离Java实现
- HDOJ 1728 逃离迷宫(DFS)
- Java实现单例模式
- gson 使用以及打包apk发布的问题
- 求最大公约数
- Reverse Bits---190
- 【4】ARM-内核制作
- C++基础--标准输入流相关
- MySQL与Oracle 差异比较之三函数
- Android Studio 设置内存大小及原理
- 堆排序