Java lambda在通过静态声明启动时陷入死锁

Java lambda在通过静态声明启动时陷入死锁,java,multithreading,lambda,static,deadlock,Java,Multithreading,Lambda,Static,Deadlock,下面的代码让我很困惑 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

下面的代码让我很困惑

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

    }

}
import java.util.function.Predicate;
公开课考试{
私有最终谓词过滤器=s->s!=null;
private boolean start=false;
私有类运行器实现可运行{
@凌驾
公开募捐{
已同步(Test.this){
开始=真;
Test.this.notifyAll();
导线测量(“”);
}
}
}
公开考试(){
System.out.println(filter.test(“”);
螺纹=新螺纹(新流道());
setDaemon(true);
thread.start();
}
公共同步字符串开始(){
而(!已启动){
试一试{
等待();
}catch(InterruptedException ex){}
}
返回“”;
}
专用同步无效遍历(字符串s){
filter.test(“”;//不计算
过滤试验;
System.out.println(“不在这里”);
}
private static final String=new Test().start();//POS1
公共静态void main(字符串[]args){
System.out.println(字符串);//POS2
}
}
它卡在
处,无法计算
。但是,如果我删除了行
POS1
,并将
POS2
改为
System.out.println(new Test().start())
,它将正常运行。在上面的代码中,如果通过静态变量启动了
Test
,则
filter
似乎不会进行计算


为什么会出现这种情况?如何解决?静态字段初始化是类初始化的一部分。在初始化静态字段和 不允许将类标记为已初始化。 当其他线程看到类状态为其他线程正在进行初始化时,它将被阻止 直到初始化完成。无法通知主线程。这会导致死锁

至于如何修复它,只需像你在问题中所说的那样在主方法中调用它

以下行来自JLS

如果C的类对象指示正在进行初始化 对于C,通过其他线程,然后释放LC并阻塞电流 线程,直到通知正在进行的初始化已完成 已完成,此时重复此步骤


将您的
start
布尔值设置为
volatile
,如果出现同样的问题,请通知我。@JacobG。不幸的是,将
started
设置为
volatile
无助于解决问题。我只是好奇,谢谢你让我知道。除此之外,我想象你的程序不知怎么地陷入了死锁,尽管我不知道为什么,除非我能够调试它并监视线程。谢谢。我还把钱放在了一些奇怪的僵局上。在过去的5个小时里,我一直在调试这个东西,但没有任何成功,我真的希望在这里获得一些见解。如果你当时还没有弄明白,我可以在几个小时内帮助你更多;祝你好运非常感谢。我已经在做噩梦了。有没有其他办法解决这个问题?我问这个问题的原因是这个类是面向公众的,我无法控制它的实现(人们可以实现
POS1
)。如何在不控制其实现的情况下防止这种潜在的死锁?@dotwin如果代码是这样编写的,那么不管您在外部做什么,死锁都会发生。如果有人这样写代码,他们就是破坏代码的人,应该对此负责。我同意你的看法。也就是说,有没有办法在内部避免/警告这种僵局?也就是说,是否有办法测试这种情况(例如,
处的死锁不计算
)并抛出错误?@dotwin您可以尝试使用静态代码分析器(sonarqube、findbugs等)。也许他们会抓住这些类型的东西。或者你可以在它们里面定义一条规则。(但是如果你不能更改代码,这将是毫无意义的)对于运行时处理,我认为你什么都做不了。