Класс Java инициализируется потоком, который использует его впервые? - PullRequest
5 голосов
/ 18 марта 2010

Допустим, определение следующих классов:

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, или, скорее, в контексте какого-то другого (специального) потока "classloader"?

Ответы [ 2 ]

5 голосов
/ 18 марта 2010

Взгляните на разделы 12.4.1 («Когда происходит инициализация») и 12.4.2 («Подробная процедура инициализации») JLS:

Тогда процедура для инициализации класса или интерфейса выглядит следующим образом:

  1. Синхронизируйте (§14.19) объект Class, который представляет класс или интерфейс, который должен быть инициализирован.Это включает ожидание, пока текущий поток не сможет получить блокировку для этого объекта (§17.1).
  2. Если инициализация для класса или интерфейса выполняется другим потоком, тогда подождите для этого объекта класса (который временно освобождаетзамок).Когда текущий поток выходит из режима ожидания, повторите этот шаг.
  3. Если текущая последовательность инициализирует класс или интерфейс для текущего потока, это должен быть рекурсивный запрос на инициализацию.Снимите блокировку с объекта Class и завершите ее обычным образом.
  4. Если класс или интерфейс уже инициализированы, дальнейшие действия не требуются.Снимите блокировку с объекта Class и завершите ее обычным образом.
    ...

В спецификации указано, что инициализация происходит в текущем потоке (то есть любой поток достиг состояния, которое вызывает необходимостьинициализировать рассматриваемый класс), но реализация JVM должна обеспечить довольно строгие гарантии синхронизации, чтобы избежать каких-либо проблем.

4 голосов
/ 18 марта 2010

Специальной темы для загрузки классов нет. Это будет из потока, который впервые обращается к классу. Метод 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();
}
...