java - 通过静态声明启动时,Java lambda 陷入死锁
问题描述
下面的代码让我很困惑。
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
通过静态变量启动。
为什么会出现这种情况,请问如何解决?
解决方案
静态字段初始化是类初始化的一部分。您在静态字段初始化期间等待(在主线程中)并且不让类被标记为已初始化。当其他线程看到类状态为其他线程正在进行初始化时,它将被阻塞,直到初始化完成。并且无法通知主线程。这会导致死锁。
至于如何修复它,只需像您在问题中所说的那样在 main 方法中调用它。
以下几行来自 JLS
如果 C 的 Class 对象指示其他线程正在对 C 进行初始化,则释放 LC 并阻塞当前线程,直到通知正在进行的初始化已完成,此时重复此步骤。
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
推荐阅读
- python - 将 shapefile 转换为地理坐标
- python - TensorFlow 高效 Cyclegan 历史池
- swift - Swift SceneKit - 如何对齐节点的 y 轴以与某些 SCNVector3 重合?
- css - 材质 UI 选项卡内的功能未触发
- java - Android 将 PCM 和 MP3 合并为 AAC
- django - Django 版本 (2.0.7) urlpatterns 语法
- javascript - 如何在 JavaScript 中动态构建列表并在 HTML 中显示
- javascript - 检测页面底部以在反应中获取更多数据
- php - Php中另一个数组中的数组
- arangodb - 使用 aql 遍历嵌套数组