initialization-on-demand holder
In software engineering, the initialization-on-demand holder (design pattern) idiom is a lazy-loaded singleton. In all versions of Java, the idiom enables a safe, highly concurrent lazy initialization of static fields with good performance.[1][2]
是一种延迟加载单例模式,所有的 Java 版本中,都能够安全、高并发的延迟初始化静态字段,并且拥有很好的性能
1 | public class Something { |
The implementation of the idiom relies on the initialization phase of execution within the Java Virtual Machine (JVM) as specified by the Java Language Specification (JLS).[3]
主要依赖于 JLS 规定的 JVM 执行的初始化阶段
When the class Something
is loaded by the JVM, the class goes through initialization. Since the class does not have any static variables to initialize, the initialization completes trivially.
当 JVM 加载类 Something 类时,会执行这个类的初始化阶段,其实就是静态字段的初始化和静态代码块的执行,但 Something 没有什么要初始化的,所以 initialize 阶段就完成了。
The static class definition LazyHolder
within it is not initialized until the JVM determines that LazyHolder
must be executed. The static class LazyHolder
is only executed when the static method getInstance
is invoked on the class Something
, and the first time this happens the JVM will load and initialize the LazyHolder
class.
LazyHolder
这个静态内部类,只有 JVM 决定这个类被执行的时候,才会进行初始化(被 JVM 加载和初始化)。所以只有 Something.
getInstance 方法调用时,当第一次调用时,JVM 会加载和初始化 LazyHolder
这个类。
The initialization of the LazyHolder
class results in static variable INSTANCE
being initialized by executing the (private) constructor for the outer class Something
. Since the class initialization phase is guaranteed by the JLS to be sequential, i.e., non-concurrent, no further synchronization is required in the static getInstance
method during loading and initialization.
LazyHolder
的初始化阶会导致静态变量 INSTANCE
被初始化,也就是执行 Something
的私有构造器。由于JLS 保证类的初始化阶段是串行的,即非并发的,因此静态getInstance方法中在加载和初始化 LazyHolder
期间不需要进一步的同步。
And since the initialization phase writes the static variable INSTANCE
in a sequential operation, all subsequent concurrent invocations of the getInstance
will return the same correctly initialized INSTANCE
without incurring any additional synchronization overhead.
所有对 getInstance
方法的连续并发调用都会返回正确的初始化了的 INSTANCE
, 并且没有任何额外的同步机制开销
While the implementation is an efficient thread-safe “singleton” cache without synchronization overhead, and better performing than uncontended synchronization,[4] the idiom can only be used when the construction of Something
can be guaranteed to not fail. In most JVM implementations, if construction of Something
fails, subsequent attempts to initialize it from the same class-loader will result in a NoClassDefFoundError
failure.
虽然高效、线程安全,但是只有保证 Something
的构造方法不会失败的情况下,才可以使用
维基百科 - initialization-on-demand holder
类的加载
类加载就是将新的类型添加到运行中的 JVM 进程里的过程。将字节码文件(.class)文件加载进 JVM, 转换成类对象(Class
分为以下几个阶段:
- 加载
从文件系统、URL或其它位置读取字节数组,生成类对象的骨架,做一些基本检查
- 验证
确认类文件与预期相符,没有违背 JVM 的安全模型,避免导致 JVM 崩溃的字节码,或将 JVM 带入未知状态,出现恶意代码能攻击的漏洞
- 准备和解析
确保运行时直到类文件引用的每个类型,加载引用到的类型,和引用类型所依赖的类,直到直到所有类型为止
- 初始化
JVM 初始化类,初始化静态变脸,运行静态代码块。这是 JVM 首次执行新加载的类的字节码。初始化执行完毕后,类就完全加载好,可以使用了。