退出应用程序优雅?

时间:2013-07-22 16:40:20

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

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

事实上,我确实希望程序在点击red-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);

确保在Exit之后从每个线程调用所有finally {}块。

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

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

3 个答案:

答案 0 :(得分:8)

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

  

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

您可以添加一个关闭钩子,如下所述:

System.exit

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

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),然后应用程序是必需的   立即终止而不等待任何清理   活动。除上述之外,还可以终止   JVM,不允许通过调用运行关闭挂钩   Runime.halt()方法。

答案 1 :(得分:3)

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

但是,实现目标的正确方法是将GUI与程序逻辑分离,就是从GUI发出一个“退出”信号,这将触发所有应用程序清理,是一个完全不同的课程。如果您有正在运行的线程,那么在每个线程中实现interrupt机制。

有许多方法可以实现退出信令。例如,您的业务代码可以为特殊事件注册GUI侦听器,这将触发清理。除了await CountDownLatch之外,您还可以拥有一个除countDown以外的任何其他内容的线程,该线程将来自GUI。{/ p>

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

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

答案 2 :(得分: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