7

我有一个具有明确定义的 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 块执行?

4

3 回答 3

8

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

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

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

Runtime.getRuntime().addShutdownHook(Thread)

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

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

警告语:

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

于 2013-07-22T16:43:01.847 回答
3

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

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

有很多方法可以实现退出信号。例如,您的业务代码可以为特殊事件注册一个 GUI 侦听器,这将触发清理。你也可以有await一个线程,它除了来自 GUI之外什么都不做。CountDownLatchcountDown

不要不惜一切代价使用关机钩子。这是可以想象的最肮脏的机制,它只是作为最后的手段,当所有常规清理程序都失败时。它永远不会被用作常规关机程序的一部分。

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

于 2013-07-22T17:00:04.787 回答
0

与现代 Java 相比,Window.dispose()在所有应用程序窗口上都可以提供更优雅的退出 AWT 应用程序的可能性System.exit(0),请参阅
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

于 2017-03-05T11:19:17.777 回答