Взаимно рекурсивно определенные статические поля вызывают замораживание программы, но не без потоков и не с gcj?
Вот простой код:
class B {final static int x = C.x;}
class C {final static int x = B.x;}
class A {
static {
System.out.println("A static{}");
new Thread() { public void run() { new B(); }}.start();
new Thread() { public void run() { new C(); }}.start();
}
public static void main(String[] args) {
System.out.println("A main");
System.out.println("B.x: " + B.x);
System.out.println("C.x: " + C.x);
}
}
B.x
и C.x
определяются в терминах друг друга. Я думал, что это не должно компилироваться, но это так.
Он зависает в main, когда я пытаюсь запустить его:
$ javac *.java && java A
A static{}
A main
Почему?
Тем не менее, он прекрасно работает в gcj:
$ gcj --main=A -o a *.java && ./a
A static{}
A main
B.x: 0
C.x: 0
Почему?
Также, если я избавлюсь от нитей,
class B {final static int x = C.x;}
class C {final static int x = B.x;}
class A {
static {
System.out.println("A static{}");
new B();
new C();
}
public static void main(String[] args) {
System.out.println("A main");
System.out.println("B.x: " + B.x);
System.out.println("C.x: " + C.x);
}
}
Он отлично работает как в java, так и в gcj:
$ javac *.java && java A
A static{}
A main
B.x: 0
C.x: 0
$ gcj --main=A -o a *.java && ./a
A static{}
A main
B.x: 0
C.x: 0
И все переменные имеют значение 0. Почему? Не должно ли это не компилироваться, так как переменные являются static final
и никогда нигде не назначаются?
1 ответ:
Вы создаете условие взаимоблокировки, которое может быть или не быть проблемой в зависимости от того, как быстро вы запускаете свои потоки.
При первом использовании класса он инициализирует класс и вызывает статические блоки. Он делает это потокобезопасным способом, и ни один другой поток не может получить доступ к классу, пока это не будет сделано.
У вас есть два потока, и в случае взаимоблокировки один имеет класс B и хочет класс C, другой имеет класс C и хочет класс B.
Как это довольно быстро, один поток может выполняться до завершения, прежде чем начнется другой, и в этом случае взаимоблокировки не происходит.
Не должно ли это не компилироваться, так как переменные являются статическими конечными и никогда нигде не назначаются?
Вы присвоили значение, однако вы получаете доступ к значению, пока оно инициализируется, поэтому вы видите значение по умолчанию 0.