【问题标题】:Is Java class initialized by the thread which use it for the first time?Java 类是由第一次使用它的线程初始化的吗?
【发布时间】:2011-01-29 00:33:09
【问题描述】:

让我们假设以下类定义:

public class A {
    public final static String SOME_VALUE;

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

public class B {
    private final String value = A.SOME_VALUE;
}

假设类 A 还没有被加载,当类 B 的对象被某个线程 T 实例化时会发生什么?类 A 必须首先加载和实例化。但我的问题是:如果它是在线程 T 的上下文中完成的,还是在其他一些(特殊)“类加载器”线程的上下文中完成的?

【问题讨论】:

    标签: java multithreading initialization classloader


    【解决方案1】:

    查看 JLS 的 12.4.1(“初始化发生时”)和 12.4.2(“详细初始化过程”)部分:

    那么初始化一个类或接口的过程如下:

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

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

    【讨论】:

      【解决方案2】:

      没有用于加载类的特殊线程。它将来自第一次引用该类的线程。 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();
      }
      

      【讨论】:

      • 我相信从 JDK7 中你可以同时初始化来自同一个类加载器的两个类。
      • @Tom 但这不会导致问题,例如如果在 equals 方法中我把 this.getClass() == obj.getClass()
      • 每个单独的类将被初始化一次,但是在同一个类加载器中可能有多个不同的类同时被初始化。由于您的答案中提到了锁定,这目前不会发生。 (我认为这是对的。)
      • 好的...我有点困惑,会检查一下。
      猜你喜欢
      • 1970-01-01
      • 2013-11-10
      • 2020-04-21
      • 2014-06-07
      • 1970-01-01
      • 1970-01-01
      • 2010-10-27
      • 2019-02-26
      • 1970-01-01
      相关资源
      最近更新 更多