Java lambda 在通过静态声明启动时陷入死锁
Java lambda trapped in deadlock when initiated through static declaration
下面的代码让我很费解
import java.util.function.Predicate;
public class Test {
private final Predicate<String> filter = s -> s != null;
private boolean started = false;
private class Runner implements Runnable {
@Override
public void run() {
synchronized ( Test.this ) {
started = true;
Test.this.notifyAll();
traverse("");
}
}
}
public Test() {
System.out.println(filter.test(""));
Thread thread = new Thread(new Runner());
thread.setDaemon(true);
thread.start();
}
public synchronized String start() {
while ( !started ) {
try {
wait();
} catch ( InterruptedException ex ) {}
}
return "";
}
private synchronized void traverse(String s) {
filter.test(""); // DOES NOT COMPUTE
filter.test(s);
System.out.println("not here");
}
private static final String STRING = new Test().start(); // POS1
public static void main(String[] args) {
System.out.println(STRING); // POS2
}
}
它卡在 DOES NOT COMPUTE
。但是,如果我删除行 POS1
并将 POS2
更改为 System.out.println(new Test().start())
,它将完美运行。在上面的代码中,filter
似乎不评估 Test
是否通过静态变量启动。
为什么会这样,请问如何解决?
静态字段初始化是class初始化的一部分。您在静态字段初始化期间正在等待(在主线程中)并且
不让 class 被标记为已初始化。
当其他线程看到 class 状态时,其他线程正在进行初始化,它将被阻塞
直到初始化完成。并且不能通知主线程。这会导致死锁。
至于如何修复,就像你在问题中所说的那样在main方法中调用它就可以了。
以下几行来自 JLS
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.
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.5
https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.4.2
https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.1.3
下面的代码让我很费解
import java.util.function.Predicate;
public class Test {
private final Predicate<String> filter = s -> s != null;
private boolean started = false;
private class Runner implements Runnable {
@Override
public void run() {
synchronized ( Test.this ) {
started = true;
Test.this.notifyAll();
traverse("");
}
}
}
public Test() {
System.out.println(filter.test(""));
Thread thread = new Thread(new Runner());
thread.setDaemon(true);
thread.start();
}
public synchronized String start() {
while ( !started ) {
try {
wait();
} catch ( InterruptedException ex ) {}
}
return "";
}
private synchronized void traverse(String s) {
filter.test(""); // DOES NOT COMPUTE
filter.test(s);
System.out.println("not here");
}
private static final String STRING = new Test().start(); // POS1
public static void main(String[] args) {
System.out.println(STRING); // POS2
}
}
它卡在 DOES NOT COMPUTE
。但是,如果我删除行 POS1
并将 POS2
更改为 System.out.println(new Test().start())
,它将完美运行。在上面的代码中,filter
似乎不评估 Test
是否通过静态变量启动。
为什么会这样,请问如何解决?
静态字段初始化是class初始化的一部分。您在静态字段初始化期间正在等待(在主线程中)并且 不让 class 被标记为已初始化。 当其他线程看到 class 状态时,其他线程正在进行初始化,它将被阻塞 直到初始化完成。并且不能通知主线程。这会导致死锁。
至于如何修复,就像你在问题中所说的那样在main方法中调用它就可以了。
以下几行来自 JLS
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.
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.5 https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.4.2 https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.1.3