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的值。
为什么会这样?
答案 0 :(得分:13)
首先从线程1(“主”线程)开始,然后开始为A
类执行静态初始化器。
在该静态初始化程序中,然后启动一个新线程(2),该线程使用A
类中的某些内容。这意味着线程2需要等到A
类完成初始化之后才能继续进行,按section 12.4.2 of the JLS:
如果C的Class对象指示某个其他线程正在对C进行初始化,则释放LC并阻止当前线程,直到通知正在进行的初始化已完成,此时重复此步骤。
但是,A
的静态初始值设定程序在 it 完成之前等待线程2完成(通过调用join()
),导致死锁:静态初始值设定项不能完成,直到线程2完成,线程2无法完成,直到静态初始化程序完成...
Upshot:不要这样做:)
答案 1 :(得分:6)
类和静态块的加载是隐式同步的。这意味着在初始化时,您无法访问另一个线程中的类中的任何内容。在这种情况下,初始化正在等待使用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)