11
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 的价值。为什么会这样?

4

2 回答 2

13

您从线程 1(“主”线程)开始,并开始执行A该类的静态初始化程序。

在该静态初始化程序中,您然后启动一个新线程 (2),它使用A类中的某些内容。这意味着线程 2 需要等到A类完成初始化才能继续,根据JLS 的第 12.4.2 节

如果 C 的 Class 对象指示某个其他线程正在对 C 进行初始化,则释放 LC 并阻塞当前线程,直到通知正在进行的初始化已完成,此时重复此步骤。

但是,您的静态初始化程序A等待直到线程 2 完成(通过调用join())才完成,从而导致死锁:静态初始化程序在线程 2 完成之前无法完成,而线程 2 在静态初始化程序完成之前无法完成...

结果:不要这样做:)

于 2013-06-21T13:33:54.210 回答
6

类和静态块的加载是隐式同步的 这意味着在初始化时,您无法访问另一个线程中的类中的任何内容。在这种情况下,初始化正在等待正在使用的线程A.i。换句话说,它正在等待第一个线程完成静态块。

注意:它不使用普通锁,并且线程声称处于可运行状态,即使它已死锁。

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)
于 2013-06-21T13:34:19.187 回答