gpt4 book ai didi

java - 带有 lambda 表达式的 invokeAndWait 在静态初始值设定项中永远挂起

转载 作者:搜寻专家 更新时间:2023-10-31 19:53:39 30 4
gpt4 key购买 nike

我偶然发现了一个使用 invokeAndWait 的问题。下面的示例代码说明了这个问题。谁能详细说明发生了什么?为什么 lambda 表达式挂起而匿名内部类和方法 ref 没有挂起。

public class Test {
// A normal (non-static) initializer does not have the problem
static {
try {
System.out.println("initializer start");

// --- Works
System.out.println("\nanonymous inner-class: Print.print");
EventQueue.invokeAndWait(new Runnable() {
@Override
public void run() {
Print.print();
}
});

// --- Works
System.out.println("\nmethod ref: Print.print");
EventQueue.invokeAndWait(Print::print);

// --- Hangs forever
System.out.println("\nlambda: Print.print");
EventQueue.invokeAndWait(() -> Print.print());

System.out.println("\ninitializer end");
} catch (Exception e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
new Test();
}
}

打印类:

public class Print {
public static void print() {
System.out.println("Print.print");
}
}

最佳答案

这是因为 lambda 表达式(部分)被编译为 Test 内部的方法,而方法引用和匿名内部类的方法则没有。

来自 Translation of Lambda Expressions :

When the compiler encounters a lambda expression, it first lowers (desugars) the lambda body into a method whose argument list and return type match that of the lambda expression, possibly with some additional arguments (for values captured from the lexical scope, if any.)

...

Method references are treated the same way as lambda expressions, except that most method references do not need to be desugared into a new method;

您可以通过查看编译类产生的字节码来验证这一点。

这很重要的原因是,当事件队列线程尝试执行通过对 lambda 主体进行脱糖创建的方法时,它会阻塞等待第一个线程完成初始化 Test,并且这两个线程会陷入死锁.

section 12.4 中描述了初始化过程JLS 的:

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • A static method declared by T is invoked.

...

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.

也在 section 5.5 中JVMS 的:

Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface that declared the resolved field or method is initialized if it has not been initialized already.

参见 this question对于没有 lambda 的类似示例。

关于java - 带有 lambda 表达式的 invokeAndWait 在静态初始值设定项中永远挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34222669/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com