为什么这段代码会产生死锁?

时间:2013-06-21 13:31:41

标签: java multithreading

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

2 个答案:

答案 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)