Java类是否由首次使用它的线程初始化?

oo_*_*_oo 5 java multithreading initialization classloader

让我们假设以下类定义:

public class A {
    public final static String SOME_VALUE;

    static {
        SOME_VALUE = "some.value";
    }
}

public class B {
    private final String value = A.SOME_VALUE;
}
Run Code Online (Sandbox Code Playgroud)

假设A类尚未加载,当某个线程T实例化B类对象时会发生什么?必须首先加载和实例化A类.但我的问题是:如果它是在线程T的上下文中完成的,或者更确切地说是在其他(特殊)"类加载器"线程的上下文中完成的?

mat*_*t b 5

查看JLS的第12.4.1节("初始化发生时")和12.4.2("详细初始化过程"):

初始化类或接口的过程如下:

  1. 在Class对象上同步(第14.19节),该对象表示要初始化的类或接口.这涉及等到当前线程可以获得该对象的锁定(第17.1节).
  2. 如果某个其他线程正在对类或接口进行初始化,则等待此Class对象(暂时释放锁定).当前线程从等待中唤醒时,重复此步骤.
  3. 如果当前线程正在对类或接口进行初始化,那么这必须是初始化的递归请求.释放Class对象上的锁定并正常完成.
  4. 如果已初始化类或接口,则无需进一步操作.释放Class对象上的锁定并正常完成.
    ...

规范声明初始化发生在当前线程中(意味着任何线程到达导致需要初始化所讨论的类的状态),但JVM实现必须做出一些非常严格的同步保证以避免任何问题.


sau*_*ata 4

没有专门的线程来加载类。它将来自第一次引用该类的线程。ClassLoader.loadClass 方法是同步的,因此尝试加载同一类的多个线程不会相互干扰。

编辑要枚举的代码

public class Arbit {
    public static void main(String[] args) throws Exception{
        B b1 = new B("1");
        B b2 = new B("2");
        B b3 = new B("3");
        b1.start();
        b2.start();
        b3.start();
        b1.join();
        b2.join();
        b3.join();
    }
}

class B extends Thread{
    B(String s){
        setName(s);
    }
    @Override
    public void run() {

        try {
            Thread.sleep(new Random().nextInt(100));
        } catch (InterruptedException e) {
        }
        System.out.println(A.s);
    }
}

class A{
    static String s = Thread.currentThread().getName();
}
Run Code Online (Sandbox Code Playgroud)