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