Java 带有lambda表达式的invokeAndWait在静态初始值设定项中永久挂起
我在使用invokeAndWait时偶然发现了一个问题。下面的示例代码说明了这个问题。有人能详细说明发生了什么事吗?为什么lambda表达式挂起而匿名内部类和方法ref不挂起Java 带有lambda表达式的invokeAndWait在静态初始值设定项中永久挂起,java,swing,lambda,Java,Swing,Lambda,我在使用invokeAndWait时偶然发现了一个问题。下面的示例代码说明了这个问题。有人能详细说明发生了什么事吗?为什么lambda表达式挂起而匿名内部类和方法ref不挂起 public class Test { // A normal (non-static) initializer does not have the problem static { try { System.out.println("initializer star
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");
}
}
注意,这个答案只是关于初始线程如何在Java8中与静态方法一起工作,它
不考虑运行时的行为
- 为了更好地理解,使用invokeLater进行的简单测试与这里的注释非常一致
- 类似于JDK8和Swing API中的bug或特性(??与删除JDK7中所有线程安全方法的bug或特性相同)
- 马丁写道——我知道我在做什么——有时调用EANDWAIT是必要的,在此之前,我从未对此有过异议从未见过这种情况,从未在今天的Java版本Java 1.6和never版本中需要使用invokeAndWait
- AWT事件队列需要对AWT/Swing JComponents进行初始化
- AWT/Swing GUI的API不能保证事件的顺序
invokeLater
输出时没有(J)个组件,一切正常,所有三个线程都成功结束invokeLater
和JFrame,一切正常,所有三个线程都以屏幕上的JFrame结束,success(这是正确的输出,唤醒它)invokeAndWait
,它永远不会从lambda表达式结束,必须从IDE中删除它invokeAndWait
和JFramepublic class Test {
// A normal (non-static) initializer does not have the problem
static {
try {
System.out.println("initializer start");
// --- Works
System.out.println("\n - anonymous inner-class: Print.print");
EventQueue.invokeLater/*EventQueue.invokeAndWait*/(new Runnable() {
@Override
public void run() {
Print.print("anonymous inner-class");
}
});
// --- Works
System.out.println("\n - method ref: Print.print");
EventQueue.invokeLater/*EventQueue.invokeAndWait*/(Print::print);
// --- Hangs forever
System.out.println("\n - lambda: Print.print");
EventQueue.invokeLater/*EventQueue.invokeAndWait*/(() -> Print.print("lambda"));
System.out.println("\n - initializer end");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Test();
}
}
及
注意,这个答案只是关于初始线程如何在Java8中与静态方法一起工作,它
不考虑运行时的行为
- 您必须使用标准的初始线程进行测试,必须使用
,否则它将失败invokeLater
- 当然,如果在运行时调用,它对您没有帮助,但是必须测试关于
- 它必须通过使用
在Java8中初始化,对于合理使用invokeLater
而言,一切似乎都只是结束——“当标准构造函数结束并从InvokeAndWait
初始化时。” e、 g 而且(Java8中的有趣笑话)与Java7或Java6相比,是否有一些JComponents并不重要invokeLater
- 没有组件
- 初始化器启动
- 匿名内部类:Print.Print
- 方法参考:Print.Print
- Print.Print从调用-匿名内部类
- lambda:
Print.Print
调用自-method refPrint.Print
- 初始值设定项结束
从-lambda调用Print.Print
- 初始化器启动
- 使用JFrame作为JComponent
- 初始化器启动
- 匿名内部类:
Print.Print
- 方法参考:
Print.Print
- lambda:
Print.Print
- 初始化器端
- Print.Print从调用-匿名内部类
****Print.Print从调用-方法参考 - Print.Print从-lambda调用
- Print.Print从-lambda调用
- 匿名内部类:
- 初始化器启动
Test
内部的方法中,而匿名内部类的方法引用和方法则不是
发件人:
当编译器遇到lambda表达式时,它首先降低
(desugars)将lambda体转换为参数列表和
返回类型与lambda表达式的返回类型匹配,可能与
附加参数(用于从词法范围捕获的值,如果需要)
任何人。)
方法引用的处理方式与lambda表达式相同,
除了大多数方法引用不需要被分解成
新方法
您可以通过查看编译类时生成的字节码来验证这一点
这一点很重要的原因是,当事件队列线程尝试执行通过对lambda主体进行去糖化而创建的方法时,它会阻止等待第一个线程完成初始化Test
,这两个线程会陷入死锁
初始化过程在JLS的第页中描述:
类或接口类型T将在
首次出现以下任何一种情况:
- 调用由T声明的静态方法
请参阅不带lambdas的类似示例。仅当您真正了解自己在做什么时才使用invokeAndWait。我知道自己在做什么-有时invokeAndWait是必要的,在此之前,我从未遇到过问题。所以它只涉及lambda?如果你改变了调用顺序,它仍然挂在lambda上?是的,你可以注释掉另外两个,lambda挂起。我可以开始看字节码,但我想我应该先问一下。-是什么触发了我,如果他们的行为都一样,我会说这是我自己的“错”-但这让我怀疑,他们的行为在我看来应该是一样的
initializer start
- anonymous inner-class: Print.print
- method ref: Print.print
- lambda: Print.print
- initializer end
* Print.print called from - anonymous inner-class
** ** Print.print called from - method ref
* Print.print called from - lambda
initializer start
- anonymous inner-class: Print.print
* Print.print called from - anonymous inner-class
- method ref: Print.print
** ** Print.print called from - method ref
- lambda: Print.print
run:
initializer start
- anonymous inner-class: Print.print
* Print.print called from - anonymous inner-class
- method ref: Print.print
** ** Print.print called from - method ref
- lambda: Print.print
BUILD STOPPED (total time: 3 minutes 40 seconds)
public class Test {
// A normal (non-static) initializer does not have the problem
static {
try {
System.out.println("initializer start");
// --- Works
System.out.println("\n - anonymous inner-class: Print.print");
EventQueue.invokeLater/*EventQueue.invokeAndWait*/(new Runnable() {
@Override
public void run() {
Print.print("anonymous inner-class");
}
});
// --- Works
System.out.println("\n - method ref: Print.print");
EventQueue.invokeLater/*EventQueue.invokeAndWait*/(Print::print);
// --- Hangs forever
System.out.println("\n - lambda: Print.print");
EventQueue.invokeLater/*EventQueue.invokeAndWait*/(() -> Print.print("lambda"));
System.out.println("\n - initializer end");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Test();
}
}
import javax.swing.JFrame;
public class Print {
public static final void print() {
/*
JFrame frame = new JFrame();
frame.setTitle("called from - method ref");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setLocationByPlatform(true);
frame.setVisible(true);*/
System.out.println(" ** ** Print.print called from - method ref");
}
public static final void print(String str) {
/*
JFrame frame = new JFrame();
frame.setTitle("called from - " + str);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setLocationByPlatform(true);
frame.setVisible(true);*/
System.out.println(" * Print.print called from - " + str);
}
}
import java.awt.EventQueue;
import java.lang.reflect.InvocationTargetException;
public class Test {
// A normal (non-static) initializer does not have the problem
static {
try {
System.out.println("initializer start");
// --- Works
System.out.println("\n - anonymous inner-class: Print.print");
EventQueue.invokeLater/*invokeAndWait*/(new Runnable() {
@Override
public void run() {
Print.print("anonymous inner-class");
}
});
// --- Works
System.out.println("\n - method ref: Print.print");
EventQueue.invokeLater/*invokeAndWait*/(Print::print);
// --- Hangs forever
System.out.println("\n - lambda: Print.print");
EventQueue.invokeLater/*invokeAndWait*/(() -> Print.print("lambda"));
System.out.println("\n - initializer end");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException, InvocationTargetException {
EventQueue.invokeAndWait(() -> Print.print("lambda"));
new Test();
}
}