6种单例模式实现
来源:互联网 发布:首次提出大数据的时间 编辑:程序博客网 时间:2024/06/05 17:21
普通懒汉式
public class Singleton { /** 单例对象 */ private static Singleton instance; /** * 私有构造方法. */ private Singleton() { } /** * 静态方法, 用于获取单利对象. * 如果单例对象未创建, 则创建新单例对象, 否则直接返回该对象. * * @return 单例对象. */ public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }}
最简单的懒汉式单例,在首次调用 getInstance(); 时,会对单例对象进行实例化。
然而,这种方式明显无法在多线程模式下正常工作。当线程并发调用getInstance(); 时,由于线程之间没有进行同步,有可能两个线程同时进入 if 条件,导致实例化两次。
线程安全的懒汉式
public class Singleton { /** 单例对象 */ private static Singleton instance; /** * 私有构造方法. */ private Singleton() { } /** * 静态方法, 用于获取单利对象. * 如果单例对象未创建, 则创建新单例对象, 否则直接返回该对象. * * @return 单例对象. */ public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }}
最简单的线程安全的懒汉模式,通过在 getInstance() 方法上添加 synchronized 关键字,保证同一时间仅有一个线程能够执行该代码段,以保证不会出现上面一种方法产生的问题。
然而,这种方法效率很低。每次调用 getInstance() 方法,都将为代码段加锁,同一时间该代码段只能被一个线程访问。然而除了首次调用外,都是不需要同步的,因为 instance 已经被实例化。
Double-Check
public class Singleton { /** 单例对象 */ private static Singleton instance; /** * 私有构造方法. */ private Singleton() { } /** * 静态方法, 用于获取单利对象. * 如果单例对象未创建, 则创建新单例对象, 否则直接返回该对象. * * @return 单例对象. */ public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }}
Double-check 即双重校验,该方法是针对上述方法提出的一种改进方案。
在 getInstance() 方法中,通过不加锁判断 instance 是否实例化。如果没有实例化,再进行加锁、实例化过程,以减少在实例化后调用 getInstance() 方法导致的性能损耗。
缺陷:instance = new Singleton()语句,看起来是一句代码,但实际上不是一个原子操作。它大致做了三件事:
1)给Singleton的实例分配内存
2)调用构造函数,初始化成员字段
3)将insance对象指向分配的内存空间
但是由于Java编译器允许处理器乱序执行,以及各种其他情况,在JDK1.5前上面的第二步和第三步没有办法保证执行顺序。当执行顺序是1-3-2时,如果执行到3后还没执行2.这时候有另一个线程调用了getInstance()方法,那么它判断到的instance不是null,它不需要经过同步代码块,直接获取到了这个错误的对象去做事去了。这就导致了错误出现。解决方法是private static Singleton instance;改为private static volatile Singleton instance;以及使用JDK1.5以上的版本。建议还是使用静态内部类的方式更好,可以规避上述问题
饿汉式
public class Singleton { /** 单例对象, 类装载时进行实例化. */ private static final Singleton singleton = new Singleton(); /** * 私有构造方法. */ private Singleton() { } /** * 静态方法, 用于获取单利对象. * * @return 单例对象. */ public static Singleton getInstance() { return singleton; }}
饿汉式单例的原理是 ClassLoader 装载类是单线程,通过这种机制避免了线程同步问题。
这种方式虽然避免了线程同步问题,但却有可能带来性能问题。
无论该类是否被使用, ClassLoader 都有可能(也有可能被 ClassLoader 忽略)加载该类并实例化该单例对象。所以在基础类库场景下,这种方法会无故消耗更多的资源。
静态内部类方式
public class Singleton { /** * 私有构造方法. */ private Singleton() { } /** * 静态方法, 用于获取单利对象. * * @return 单例对象. */ public static Singleton getInstance() { return SingletonHolder.instance; } private static class SingletonHolder { /** 单例对象, 类装载时进行实例化. */ private static final Singleton instance = new Singleton(); }}
这种方法同样利用了 ClassLoader 单线程装载的方式,避免了线程同步问题。然而他和上面一种方法不同的地方在于, instance 对象只有在 SingletonHolder 类被装载的时候才会被实例化。也就是说,只有当 getInstance() 方法调用时,才会被实例化,这样就避免了上述的资源损耗。
枚举方式
public enum Singleton { INSTANCE; }
- 6种单例模式实现
- 【Swift】3种单例模式实现详解
- java中4种单例模式实现方法
- java中5种单例模式的实现
- 质量保证的六个模式(6) - 架构和实现模式
- 设计模式C++实现(6)——适配器模式
- 大话设计模式C++实现-第6章-装饰模式
- 设计模式学习(C++实现)6--桥接模式
- 开发模式:实现Command模式
- 实现设计模式:观察者模式
- 实现设计模式:工厂模式
- 实现设计模式:原型模式
- 实现设计模式:命令模式
- 实现设计模式:访问者模式
- 策略模式模式C++实现
- 实现Prototype设计模式
- Adapter模式AS2实现
- 实现Prototype设计模式
- oscache缓存配置
- 16.7.12
- WLAN的一些术语
- java学习笔记1
- 替代ByteArrayBuffer 解决missing in SDK23的问题
- 6种单例模式实现
- 22.Generate Parentheses
- viewPaper+Fragment的布局,在初始化时会导致fragment的布局加载和网络请求数据(懒加载)
- 仿QQ5.0侧滑先行版
- 文字上下轮播
- Android的多分辨率适配的处理
- Iterator<Entry<String, HashMap<String, String>>>
- 如何测试Azure虚拟机网络连通性(默认禁Ping)
- HIVE(下)