static块初始化

参考

静态块的执行时机

每当发生以下事件之一时,ClassLoader 都需要加载 Class:

  • 静态成员变量由应用程序设置(应用程序是指包含静态块的类之外的代码)
  • 应用程序访问非最终静态成员变量
  • 应用程序调用静态方法
  • Class.forName("...")
  • 使用 Class.newInstance() 或通过 new 关键字创建实例

由于静态块的使用是在类的初始化/加载中(应该只发生一次),因此该块被 JVM 视为“同步”块。只有当类状态为“未初始化”时,线程才能访问此代码块。由于有多个上述事件可以触发类加载,JVM 需要确保类加载/初始化只发生一次。为了确保这一点,每个类都有一个“初始化锁”,它由首先到达静态块的线程获取,并且只有在静态块代码执行完成后才会释放锁。

在此之前,其他线程在任何活动上都会被阻塞,例如尝试加载类或创建实例。一旦锁被释放,类的状态被设置为“完全初始化”,不需要任何其他线程进入静态块。

初始化锁举例

Test.java

public class Test {
    static {
        System.out.println("Entered static block by thread " + Thread.currentThread().getName());
        try {
            Thread.sleep(10000);
            System.out.println("Finished static block by thread " + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(() -> Class.forName("org.priya.Test"));
        executorService.submit(() -> {
            final Test test = new Test();
            System.out.println("Object created by thread " + Thread.currentThread().getName());
        });
    }
}

初始化锁导致的死锁

当一个类中的静态块代码触发另一个类的类加载事件,那个类中也有一个静态块,静态块又依赖于当前类,就会引入死锁,导致java.lang.ClassNotFoundException异常。

死锁代码

posted @ 2022-03-26 15:41  wuzu  阅读(127)  评论(0编辑  收藏  举报