为什么这段代码会产生死锁?(复制)

时间:2023-01-14 09:03:15

This question already has an answer here:

这个问题已经有了答案:

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");
    }
}

I never get finish get printed and value of i. Why is it so?

我从来没有完成被打印和价值的我。为什么是这样?

2 个解决方案

#1


13  

You start off on thread 1 (the "main" thread), and start executing the static initializer for the A class.

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

Within that static initializer, you then start a new thread (2), which uses something within the A class. That means that thread 2 needs to wait until the A class has finished initilaizing before it will proceed, as per section 12.4.2 of the JLS:

在静态初始化器中,然后启动一个新的线程(2),它使用a类中的某些东西。这意味着线程2需要等到A类完成初始化后才能继续进行,如JLS的12.4.2节所示:

If the Class object for C indicates that initialization is in progress for C by some other thread, then release LC and block the current thread until informed that the in-progress initialization has completed, at which time repeat this step.

如果C的类对象表示初始化是由其他线程在C的进程中进行的,那么释放LC并阻塞当前线程,直到通知了正在进行的初始化已经完成,这时重复这个步骤。

However, your static initializer for A waits until thread 2 has completed (by calling join()) before it completes, leading to deadlock: the static initializer can't complete until thread 2 has completed, and thread 2 can't complete until the static initializer has completed...

但是,您的静态初始化器等待线程2完成(通过调用join())来完成它,导致死锁:直到线程2完成静态初始化器才能完成,线程2直到静态初始化器完成为止……

Upshot: don't do this :)

结论:不要这样做

#2


6  

Loading of classes and static blocks are implicitly synchronized This means you cannot access anything in a class in another thread while it is being initialised. In this case the initialisation is waiting for a thread which is using A.i. In other words, it is waiting for the first thread to finish the static block.

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

Note: it doesn't use a normal lock and the thread claims to be in a Runnable state even though it is deadlocked.

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

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)

#1


13  

You start off on thread 1 (the "main" thread), and start executing the static initializer for the A class.

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

Within that static initializer, you then start a new thread (2), which uses something within the A class. That means that thread 2 needs to wait until the A class has finished initilaizing before it will proceed, as per section 12.4.2 of the JLS:

在静态初始化器中,然后启动一个新的线程(2),它使用a类中的某些东西。这意味着线程2需要等到A类完成初始化后才能继续进行,如JLS的12.4.2节所示:

If the Class object for C indicates that initialization is in progress for C by some other thread, then release LC and block the current thread until informed that the in-progress initialization has completed, at which time repeat this step.

如果C的类对象表示初始化是由其他线程在C的进程中进行的,那么释放LC并阻塞当前线程,直到通知了正在进行的初始化已经完成,这时重复这个步骤。

However, your static initializer for A waits until thread 2 has completed (by calling join()) before it completes, leading to deadlock: the static initializer can't complete until thread 2 has completed, and thread 2 can't complete until the static initializer has completed...

但是,您的静态初始化器等待线程2完成(通过调用join())来完成它,导致死锁:直到线程2完成静态初始化器才能完成,线程2直到静态初始化器完成为止……

Upshot: don't do this :)

结论:不要这样做

#2


6  

Loading of classes and static blocks are implicitly synchronized This means you cannot access anything in a class in another thread while it is being initialised. In this case the initialisation is waiting for a thread which is using A.i. In other words, it is waiting for the first thread to finish the static block.

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

Note: it doesn't use a normal lock and the thread claims to be in a Runnable state even though it is deadlocked.

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

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)