initialization on demand holder 模式分析
单例模式要求在应用运行的过程中,只有一个类的实例存在。因此,要确保创建过程是线程安全的,同时要兼顾性能。目前了解到做得比较好的,就是这种initialization on demand holder模式(简称holder模式)。holder模式巧妙使用虚拟机的类加载和初始化机制来实现延迟加载和保证创建过程线程安全。
首先看下holder模式:
public class BestSingleton {//构造方法一定要设为privateprivate BestSingleton(){}private static class LazyLolder{private static final BestSingleton INSTANCE = new BestSingleton();}public static BestSingleton getInstance(){return LazyLolder.INSTANCE;}
}
然后,分析运行 BestSingleton.getInstance()
语句的过程:
1. ClassLoader加载BestSingleton类,并初始化,由于BestSingleton类不存在任何域,初始化看起来没有做任何事。
2. 调用BestSingleton类的getInstance()
方法,至此,LazyLolder类的调用第一次出现。因为调用的是一个静态域,因此要执行LazyLolder类的静态初始化。
3. 静态初始化LazyLolder类,也就是对INSTANCE 变量进行初始化,实例化一个BestSingleton类的实例,并赋值给INSTANCE 。
4. 继续执行getInstance()
方法的返回语句。
关键是在第三步,jvm对类的初始化过程是一个串行,单线程的过程,所以不会有并发的问题。
hoader模式失败案例
这个单例模式还是有失败的时候,不过个人觉得很好会遇到吧。在参考3里可以看到失败例子。
jvm类加载和初始化过程简要
jvm第一次用到一个类的时候,如果类还未加载,则找到该类的class文件并加载该类。每个类都对应一个class文件,内部类也是如此。
第一次使用可以分为:
- 创建一个类的实例,要对实例化。
- 使用用类的静态域或方法,要进行静态初始化。
根据不同的使用类型进行不同初始化。
静态初始化:
- 对类变量(静态变量)进行初始化
- 执行静态初始化语句,也就是static语句块中包含的语句。
静态初始化不会调用类的构造方法,构造方法只有在类实例化的时候才会调用。
实例化
- 进行静态初始化
- 对实例变量进行初始化
- 执行初始化语句块,也就是用{}括起来的语句块
- 执行构造方法
参考资料:
- Java单例模式的各种写法(Initialization on Demand Holder模式)
- 线程安全的单例模式
- Initialization-on-demand holder idiom