类的初始化
一个正常的类初始化过程
如果父类还没有完成初始化,则先完成父类的初始化;
Class对象处于被链接过,还未初始化的状态;- 获取锁
LC->记录Class对象的状态为初始化过程中->释放锁LC;Class对象的状态为初始化过程中- 将
class文件中的ConstantValue属性中记录的常数值依次赋值给每个final、static字段;- 执行类
C的<clinit>方法;- 如果类
C的<clinit>方法正常完成,则获取锁LC->记录Class对象的状态为已完成初始化->通知所有等待线程->释放锁LCClass对象的状态为已完成初始化- 如果类
C的<clinit>方法执行报错,则则获取锁LC->记录Class对象的状态为初始化报错->通知所有等待线程->释放锁LCClass对象的状态为初始化报错
如何在并发多线程环境里保证上述初始化过程的线程安全?
假设有两个线程A和线程B,线程A和线程B都执行到步骤2,开始竞争锁LC。
方法一:
假设线程A在竞争中获得了锁LC,则记录Class对象的状态为被线程A控制的初始化过程中,然后释放了锁。然后,不管在后面的哪一步被抢占,都执行如下操作:如果线程B获得了锁LC,发现Class对象的状态为被线程A控制的初始化过程中,则线程B就释放锁LC,开始等待一直到收到线程A完成Class对象初始化的通知,正常完成。
哪些情形会触发类的初始化?
- 虚拟机启动时触发
initial类的初始化 - 子类的初始化触发父类的初始化
- 调用类库中的反射方法
- 首次调用
java.lang.invoke.MethodHandle实例 - 虚拟机执行
new、getstatic、putstatic、invokestatic中任意一个指令