Java Swing应用程序意外终止

时间:2013-07-20 09:13:45

标签: java swing google-app-engine terminate event-loop

我正在尝试使用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 Dev-Server的助手类:

// 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有了一些非常奇怪的行为:

  1. 首先,Swing的工作方式:如果我在DevServer.launch(...)注释掉行main(...),应用程序启动,显示调试窗口,继续运行,当我关闭调试窗口时,它关闭。
  2. 如果我重新添加DevServer.launch(...),它会按预期启动服务器,然后立即退出(它可能还会短暂显示调试窗口,但它太快看不到了。)
  3. 如果我在DevServer.launch(...)之后移动SwingUtilities.invokeLater(...)行,它会显示调试窗口,然后启动服务器,当服务器启动时,它会立即退出。
  4. 现在变得非常奇怪:如果我将行更改为DevServer.launch(args, false),即我不等待服务器实际启动,而只是让我的main(...)方法立即完成,调试窗口显示,服务器正确加载,应用程序继续运行,但是如果我关闭调试窗口则不退出?!
  5. 如果我还将JFrame.DISPOSE_ON_CLOSE更改为JFrame.EXIT_ON_CLOSE,则调试窗口显示,服务器正确加载,应用程序继续运行,如果我关闭调试窗口,它将正确退出。
  6. 知道这里的Swing事件循环是怎么回事吗?我很难过......有什么东西会导致Swing事件循环提前终止(场景2和3)?多线程应用程序是否阻止Swing检测到最后处理的窗口(方案4)?

    供参考,here is the source of the Google AppEngine Dev Server

1 个答案:

答案 0 :(得分:1)

第4项和第5项实际上是预期的行为。当放置最后一个Swing窗口时,Java / Swing应用程序不会停止,但是当最后一个线程停止执行时。这两个条件对于单线程应用程序是等效的,但不适用于多线程应用程序。

对于#1,#2和#3:通过AppEngine开发服务器代码查看,我注意到有相当数量的System.exit(int)次呼叫。其中一个可能是罪魁祸首。如果您显示的代码是相关的,那么可能会在System.exit(由于#4)之后建立的连接中调用有问题的if (!waitFor) return;