4

我正在尝试用 Java 编写一个还运行 Google AppEngine Dev-Server 的 Swing 应用程序(请参阅开发使用 AppEngine 数据库的 Java 应用程序)并且遇到了 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_CLOSEJFrame.EXIT_ON_CLOSE,则显示调试窗口,服务器加载正确,应用程序继续运行,如果我关闭调试窗口,它会正确退出。

知道 Swing 事件循环在这里发生了什么吗?我被难住了......是否有什么事情会导致 Swing 事件循环提前终止(场景 2 和 3)?多线程应用程序是否会阻止 Swing 检测到最后释放的窗口(场景 4)?

作为参考,这里是 Google AppEngine Dev Server 的来源

4

1 回答 1

1

项目#4 和#5 实际上是预期的行为。Java/Swing 应用程序不会在最后一个 Swing 窗口被释放时停止,而是在最后一个线程停止执行时停止。这两个条件对于单线程应用程序是等价的,但对于多线程应用程序则不然。

至于 #1、#2 和 #3:查看 AppEngine Dev Server 代码,我注意到其中有相当多的System.exit(int)调用。其中之一可能是罪魁祸首。如果您显示的代码是所有相关的,那么System.exit可能会调用违规行为以响应之后建立的连接if (!waitFor) return;(由于#4)

于 2013-07-20T09:31:38.403 回答