This question already has an answer here:
这个问题已经有了答案:
- Deadlock caused by thread.join() in a static block 1 answer
- 由线程.join()在静态块1答案中引起的死锁
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)