【问题标题】:Exiting an application gracefully?优雅地退出应用程序?
【发布时间】:2013-07-21 12:06:37
【问题描述】:

我有一个具有明确定义的 Try/Catch/Finally 链的应用程序,它在正常情况下退出并执行 finally 块就好了,但是当有人过早地在 GUI 中点击红色 X 时,程序完全存在(代码 = 0 ) 并且不会调用主线程的 finally 块。

事实上,我确实希望程序在单击红色 X 时退出,但我不希望跳过 finally{} 块!我在 GUI 中手动放入了 finally 块中最重要的部分,但我真的不想这样做,因为我希望 GUI 与实际程序分离:

class GUI { // ...
...
mainFrame.addWindowListener(new WindowAdapter() {
  public void windowClosing(WindowEvent evt) {
    try {
      processObject.getIndicatorFileStream().close();
    } catch (Exception ignore) {}
    System.exit(0);
  }
});
...
}

但我更喜欢这样的电话:

mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

并确保在退出后从每个线程调用所有 finally{} 块。

我知道这实际上是意料之中的。如果应用程序从一个单独的线程(比如 GUI 线程)关闭,那么主线程将停止在其轨道上。

简而言之——我如何确保 System.exit(0) 或 JFrame.EXIT_ON_CLOSE 仍会导致每个线程的 finally 块执行?

【问题讨论】:

    标签: java user-interface jframe exit try-catch-finally


    【解决方案1】:

    如果您没有其他设计更改选择,那么您可能需要一个 JVM 关闭挂钩,可以添加它以在 System.exit 时运行一段代码被调用。

    Shutdown Hooks 是一种特殊的构造,允许开发人员插入 在JVM关闭时要执行的一段代码中。这 在我们需要进行特殊清理的情况下派上用场 虚拟机关闭时的操作。

    您可以按此处所述添加关闭挂钩:

    Runtime.getRuntime().addShutdownHook(Thread)
    

    在此处阅读有关关闭挂钩的更多信息:

    http://java.dzone.com/articles/know-jvm-series-2-shutdown

    注意事项:

    我们必须记住的是,不能保证关机 挂钩将始终运行。如果 JVM 由于某些内部错误而崩溃, 那么它可能会崩溃而没有机会执行单个 操作说明。此外,如果操作系统发出 SIGKILL (http://en.wikipedia.org/wiki/SIGKILL) 信号(在 Unix/Linux 中杀死 -9) 或 TerminateProcess (Windows),则应用程序需要 立即终止,甚至不等待任何清理 活动。除了上述之外,还可以终止 JVM 不允许关闭挂钩通过调用运行 Runime.halt() 方法。

    【讨论】:

    • 可能需要注意的是,它不能保证始终运行(例如,当 jvm 崩溃时)。
    • @damo 是的,这很重要。让我把它添加到答案中
    • 这是个坏建议。关闭挂钩应该从不用作常规退出例程的一部分。它们只是在所有其他方法都失败时的最后手段,以挽救可以挽救的东西。
    【解决方案2】:

    如果你碰巧有这样的线程可以在任何时候合法地停止,在它们循环中的任何点,在它们调用的任何方法中的任何点,我可以警告你你不太可能这样做,那么你可以在程序退出时stop所有这些。这将导致在每个线程中抛出异常,并执行finally 块。

    然而,实现您的目标的正确方法将 GUI 从程序逻辑中解耦,是从 GUI 发出单个“退出”信号,这将触发所有应用程序清理,这是在一个完全不同的类中编写的。如果您有正在运行的线程,则在每个线程中实现interrupt 机制。

    有很多方法可以实现退出信号。例如,您的业务代码可以为特殊事件注册一个 GUI 侦听器,这将触发清理。您还可以在CountDownLatch 上创建一个除了await 之外什么都不做的线程,这将是GUI 中的countDown

    不要使用关闭挂钩。这是可以想象的最肮脏的机制,它只是作为最后的手段,当所有常规清理程序都失败时。 从不用作常规关机程序的一部分。

    总而言之,没有清除应用程序关闭的有效方法。您必须针对每个特定问题实施特定机制。

    【讨论】:

    • 任何示例代码?我听到你在说什么,这听起来很合乎逻辑(我基本上是在寻找这件事的例子)
    • 你能详细说明一下吗,或者给谷歌一些链接或短语?
    • @hoto Thread#interrupt 是谷歌的一件事; CountDownLatch 是另一个; AWT custom event 是第三个。
    【解决方案3】:

    对于现代 Java,所有应用程序窗口上的 Window.dispose() 可以提供比 System.exit(0) 更优雅的退出 AWT 应用程序的可能性,请参阅
    https://docs.oracle.com/javase/8/docs/api/java/awt/Window.html#dispose--

    /** Listens and closes AWT windows.
     * The class is implemented as singleton since only one is needed.
     */
    public class ExitListener extends WindowAdapter {
    
      /** the instance object */
      private static final ExitListener INSTANCE = new ExitListener();
    
      // hide the constructor
      private ExitListener () {}
    
      /** retrieve the listener object */
      public static ExitListener getInstance () {
        return INSTANCE;
      }
    
      @Override
      public void windowClosing ( final WindowEvent e ) {
        e.getWindow().dispose();
      }
    }
    

    和你的窗户

    window.addWindowListener( ExitListener.getInstance() );
    

    但是,在恶劣的环境中要小心,请参阅:
    https://docs.oracle.com/javase/8/docs/api/java/awt/doc-files/AWTThreadIssues.html#Autoshutdown

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多