我正在尝试用 Java 编写一个 Swing 应用程序,该应用程序还运行 Google AppEngine Dev-Server(请参阅 Developing a Java Application that uses an AppEngine database),但我遇到了 Swing Eventloop 的一个奇怪问题。
我有以下两个类:
一个调试窗口,它最终会接收日志消息等:
public class DebugWindow {
private static JFrame debugWindow = null;
private static JTextArea debugContent = null;
public static void show() {
debugWindow = new JFrame("Debug");
debugWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
debugContent = new JTextArea("Debug messages go here!");
debugWindow.add(debugContent, BorderLayout.CENTER);
debugWindow.pack();
debugWindow.setVisible(true);
}
}
加载 Google AppEngine 开发服务器的辅助类:
// other imports
import com.google.appengine.tools.development.DevAppServerMain;
public class DevServer {
public static void launch(final String[] args, boolean waitFor) {
Logger logger = Logger.getLogger("");
logger.info("Launching AppEngine server...");
Thread server = new Thread() {
@Override
public void run() {
try {
DevAppServerMain.main(args); // run DevAppServer
} catch (Exception e) { e.printStackTrace(); }
}
};
server.setDaemon(true); // shut down server when rest of app completes
server.start(); // run server in separate thread
if (!waitFor) return; // done if we don't want to wait for server
URLConnection cxn;
try {
cxn = new URL("http://localhost:8888").openConnection();
} catch (IOException e) { return; } // should never happen
boolean running = false;
while (!running) {
try {
cxn.connect(); // try to connect to server
running = true;
} catch (Exception e) {}
}
logger.info("Server running.");
}
}
我的 main(...)
方法如下所示:
public static void main(final String[] args) throws Exception {
DevServer.launch(args, true); // launch and wait for AppEngine dev server
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
DebugWindow.show(); // create and show debug window
}
});
}
有了这个,我得到了一些关于 Swing Eventloop 的非常奇怪的行为:
- 首先,Swing 应该如何工作:如果我注释掉
main(...)
中的DevServer.launch(...)
行,应用程序将启动, 显示调试窗口,继续运行,当我关闭调试窗口时,它会关闭。 - 如果我重新添加
DevServer.launch(...)
,它会按预期启动服务器,然后立即退出(它可能还会短暂地显示调试窗口,但速度太快了见)。 - 如果我在
SwingUtilities.invokeLater(...)
之后移动DevServer.launch(...)
行,它会显示调试窗口,然后启动服务器,当服务器启动时,它会立即退出。 - 现在真的很奇怪:如果我将行更改为
DevServer.launch(args, false)
,即我不等待服务器实际启动,而只是让我的main(...)
方法立即完成,调试窗口显示,服务器正确加载,应用程序继续运行,但如果我关闭调试窗口不会退出?! - 如果我随后也将
JFrame.DISPOSE_ON_CLOSE
更改为JFrame.EXIT_ON_CLOSE
,则调试窗口显示,服务器正确加载,应用程序继续运行,如果出现以下情况,它会正确退出我关闭调试窗口。
知道这里的 Swing 事件循环发生了什么吗?我很难过......是否有什么会导致 Swing 事件循环提前终止(场景 2 和 3)?多线程应用程序是否会阻止 Swing 检测最后处理的窗口(场景 4)?
最佳答案
项目 #4 和 #5 实际上是预期的行为。 Java/Swing 应用程序不会在最后一个 Swing 窗口被释放时停止,而是在最后一个线程停止执行时停止。这两个条件对于单线程应用是等价的,但对于多线程应用则不是。
至于 #1、#2 和 #3:查看 AppEngine Dev Server 代码,我注意到其中有相当多的 System.exit(int)
调用。其中之一可能是罪魁祸首。如果您显示的代码都是相关的,那么可能会调用有问题的 System.exit
以响应 if (!waitFor) return;
之后建立的连接(由于 #4)
关于Java Swing 应用程序意外终止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17760659/