【发布时间】:2014-05-11 14:55:00
【问题描述】:
所以基本上我会为我的应用程序更新 GUI,所以我使用静态方法
void javax.swing.SwingUtilities.invokeLater(Runnable doRun)
但我希望将我的初始化代码放在可运行文件中,而将逻辑代码放在外面。但是,如果我调用 invokeLater 方法,我的主线程和 AWT 线程将处于竞争状态,因为我的主线程将在调用 invokeLater 方法之后尝试调用我的逻辑代码,但由于JFrame(就我而言)尚未初始化,因此我的主线程很可能会赢得比赛并因此引发异常。
我认为我可以等待可运行对象被事件调度线程执行,然后在可运行对象初始化初始化代码时通知它。但是由于某种原因,下面的代码(缩写)不起作用。
对于轻量级应用程序,runnable 可能会赢得竞争条件,因此不会产生任何异常,但在我的应用程序中,初始化代码更长。
SSCCE:
public class SSCCE {
private static JFrame frame;
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
synchronized (this) {
frame = new JFrame();
frame.setTitle("JFrame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
this.notifyAll();
System.out.println("Notified all");
}
}
};
synchronized (r) {
try {
System.out.println("Waiting"); // EDIT this line was after the wait method, and therefore it didn't execute.
r.wait();
} catch (InterruptedException e) {
throw new RuntimeException("Unexpected disruption whilst waiting for the \"Event-Dispatching thread\".",e);
}
}
SwingUtilities.invokeLater(r);
frame.setVisible(true);
frame.getContentPane().add(new JLabel("Hello World!"));
frame.pack();
}
}
提前致谢!
【问题讨论】:
-
抱歉,这背后的动机是什么?
-
所有 Swing GUI 代码都应该在事件调度线程上执行。使用 invokeLater() 的目的是向 EDT 添加代码。无需同步您的 Runabble。我真的认为你把事情复杂化了。只需将所有代码放入 EDT。如果您有一个长时间运行的任务,那么您可以在 GUI 已经创建并使其可见后从您的 init 代码中调用该任务。
-
@HovercraftFullOfEels 我正在创建一个将更新 GUI 的应用程序,并且 invokeLater 应该在 AWT 事件调度线程上异步运行主线程,但是因为我试图直接访问 JFrame之后,它会抛出一个异常,因为它还没有被初始化。
-
Linus,你告诉我们的 Y 部分听起来像是 XY Problem——你计划的代码解决方案——一个可能完全错误的计划。我想知道 X 部分,需要这样一个方案的基本原理。
-
@camickr 那么,创建一个像
CreateAndShowGUI这样的方法是我应该做的吗?然后在初始化代码之后从我的可运行文件中调用它?
标签: java multithreading swing race-condition