1. 预热
为了小伙伴们能够比较好的理解后面讲解,先将一些前置的概念在这里进行预热,假如你已经知道这里概念,你可以跳过这个小结。
- 指令序重排:Java内存模型中,允许编译器和处理器对指令进行重排序,重排序过程不会影响到单线程程序的执行,会影响到多线程并发执行的正确性
- volatile 可见性生命:内存屏障和禁止重排序优化来实现
2. 实现方法分析
实现单例模式估计是全地球人都知道的设计模式了,它又有懒汉模式和饿汉模式之分,区别在于对单例对象初始化的时机不同,懒汉模式顾名思义,比较懒,所以对象的初始化会放到使用的那一个刻才会进行!饿汉反之,具体孰好孰坏,这个得两说,就饿汉来说,如果单例对象比较轻(废话,要是很轻还用单例搞鬼么)和初始化比较快且后续一定使用的话,这个就无所谓了!比较推荐,但是如果不用,这样就有点浪费服务器的性能和资源了!接下来我会提供这两种模式的几种实现方式!
a) 懒汉模式
/** * 两种经典的饿汉式实现 * * @author Lin.Jianfei * @version 1.0.0 * @since 2018-05-07 */ class Singleton4Eager1 { private Singleton4Eager1() {} private static Singleton4Eager1 INSTANCE = new Singleton4Eager1(); public static Singleton4Eager1 getInstance() { return INSTANCE; } } class Singleton4Eager2 { private Singleton4Eager2() {} // 需要注意静态代码的顺序,静态代码块是按照编写的顺序执行 private static Singleton4Eager2 INSTANCE = null; static { INSTANCE = new Singleton4Eager2(); } public static Singleton4Eager2 getInstance() { return INSTANCE; } }
b) 懒汉式
class Singleton4Lazy1 { private Singleton4Lazy1() {} private Singleton4Lazy1 instance = null; // 线程不安全 public Singleton4Lazy1 getInstance() { if (instance == null) { instance = new Singleton4Lazy1(); } return instance; } } class Singleton4Lazy2 { private Singleton4Lazy2() {} private Singleton4Lazy2 instance = null; // 线程安全,效率低下 public synchronized Singleton4Lazy2 getInstance() { if (instance == null) { instance = new Singleton4Lazy2(); } return instance; } } class Singleton4Lazy3 { private Singleton4Lazy3() {} // 这里加上 volatile 修饰,禁止指令优化重排 private volatile Singleton4Lazy3 instance = null; // 线程安全,引入 volatile + 双重校验 改善并发性能, public synchronized Singleton4Lazy3 getInstance() { if (instance == null) { synchronized (Singleton4Lazy3.class) { if (instance == null) { instance = new Singleton4Lazy3(); } } } return instance; } } class Singleton4Lazy4 { private Singleton4Lazy4() {} private Singleton4Lazy4 instance = null; public Singleton4Lazy4 getInstance() { return InnerSingleton.INSTANCE.getInstance(); } private enum InnerSingleton { INSTANCE; private Singleton4Lazy4 instance; // 利用虚拟机特性,保证延迟且只执行一次创建,避免的使用锁,性能最好 InnerSingleton() { this.instance = new Singleton4Lazy4(); } public Singleton4Lazy4 getInstance() { return this.instance; } } }
3. 总结
这里,实现饿汉式有好多种方式可以实现,可以根据自己的业务场景需要进行选择,如果是单线程的场景,无疑是第一种最好,类似StringBuilder 和 StringBuffer。假如涉及到并发的话,建议采用最后用枚举方式的实现,即避免了锁的损耗且延迟加载!