Java 一个线程能否在另一个线程完成静态初始化(类加载)之前进入静态方法?

Java 一个线程能否在另一个线程完成静态初始化(类加载)之前进入静态方法?,java,multithreading,deadlock,static-initializer,Java,Multithreading,Deadlock,Static Initializer,假设我们有以下类和两个线程t1,t2 public class A { static String str = "abc"; static { B.bMeth(); } static void aMeth() { System.out.println("A::meth()"); str = "abc2"; } static vo

假设我们有以下类和两个线程t1,t2

public class A {
        static String str = "abc";

        static {
          B.bMeth();
        }

        static void aMeth() {
            System.out.println("A::meth()");
            str = "abc2";
        }

        static void aSomeMeth() {}
    }

public class B {

        static {
            A.aMeth();
        }

        static void bMmeth() {}
        static void bSomeMeth() {}
    }
以下是死锁发生的顺序:

1) t1执行一个.asomeeth(),它在为A加载类时获得锁

2) t2执行B.bSomeMeth(),它在为B加载类时获取锁

3) t1继续执行B.bMeth(),并在保持A的锁的同时要求B的锁

4) t2继续执行A.aMeth(),并要求锁定A,同时保持锁定B

这会导致死锁。但是在我的例子中,t2实际上进入了
aMeth
(),并且在访问静态成员
str
时被阻止。所以我想知道在特殊条件下,线程在初始化之前是否可能进入静态方法


在我的测试运行中,t2总是像预期的那样在A.amethy()处被阻塞,因此可能会有任何情况下它可以进入并在
str
、JIT优化(如方法内联等)上被阻塞。

不,一个类只能由一个线程初始化一次。如果另一个线程访问同一个类,这个线程将在初始化完成时阻塞。

对,因此理想情况下t2应该在
aMeth
()上阻塞,但是JIT可以为
aMeth
()进行方法内联,所以B的静态块看起来像公共类B{static{System.out.println(“A::meth()”);A.str=“abc2”}}因此t2将在访问静态实例的行上被阻塞
str
。现在进行一个线程堆栈跟踪,它将在方法
aMeth
()中显示t2。不,这不会发生,原因有几个:当加载类时,加载代码仍在被解释。JIT代码不包含任何类加载处理,因为它依赖于所有初始化工作已经完成。否则,它将阻碍许多优化。而且,JIT必须(!)保持代码的相同行为。“一次”误导性地造成了这样一种印象,即这个过程可能不止一次,一次只能发生一个线程。此外,我将“loaded”改为“initialized”,因为加载和初始化是两件不同的事情,不一定由同一个线程完成,问题在于初始化(但这两件事情只能发生一次)。