Почему этот код создает тупик?
class A {
static final int i;
static {
i = 128;
Thread t = new Thread() {
public void run() {
System.out.println("i=" + i);
}
};
t.start();
try {
t.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public class MainTesting {
public static void main(String[] args) {
A a = new A();
System.out.println("finish");
}
}
Я никогда не получаю finish
печатать и значение i.
Почему это так?
Ответы
Ответ 1
Вы начинаете с потока 1 ( "основной" поток) и начинаете выполнение статического инициализатора для класса A
.
Внутри этого статического инициализатора вы затем запускаете новый поток (2), который использует что-то в классе A
. Это означает, что поток 2 должен ждать, пока класс A
завершит инициализацию до того, как он продолжит, согласно разделу 12.4.2 JLS:
Если объект класса для C указывает, что инициализация выполняется для C каким-либо другим потоком, затем отпустите LC и заблокируйте текущий поток, пока не сообщите, что завершенная инициализация завершена, и в этот момент повторите этот шаг.
Однако ваш статический инициализатор для A
ждет, пока поток 2 не завершит (вызывая join()
) до его завершения, что приведет к тупиковой ситуации: статический инициализатор не может завершиться до тех пор, пока поток 2 не завершится, а поток 2 может 't до завершения статического инициализатора...
Результат: не делайте этого:)
Ответ 2
Загрузка классов и статических блоков неявно синхронизируется. Это означает, что вы не можете получить доступ к чему-либо в классе в другом потоке, пока он инициализируется. В этом случае инициализация ожидает поток, который использует A.i
. Другими словами, он ждет, пока первый поток завершит статический блок.
Примечание: он не использует нормальную блокировку, и поток утверждает, что находится в состоянии Runnable, даже если он заблокирован.
2013-06-21 11:20:40
Full thread dump Java HotSpot(TM) 64-Bit Server VM (23.21-b01 mixed mode):
"Thread-0" prio=6 tid=0x000000000d55d000 nid=0x3cc4 in Object.wait() [0x000000000dbdf000]
java.lang.Thread.State: RUNNABLE
at Main$1.run(Main.java:14) <- where A.i is referenced.
"main" prio=6 tid=0x00000000022df000 nid=0x3284 in Object.wait() [0x000000000257e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007d5610448> (a Main$1)
at java.lang.Thread.join(Thread.java:1258)
- locked <0x00000007d5610448> (a Main$1)
at java.lang.Thread.join(Thread.java:1332)
at Main.<clinit>(Main.java:19)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:188)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:113)