我有一个使用addShutdownHook()处理Ctrl + C的Swing应用程序,它可以正常工作,直到我调用的一个关闭任务在正常情况下会更改JLabel文本,此时它会挂起。
我认为问题在于Swing EDT已经终止或正在等待某事。
有没有办法确定EDT已经终止或者已经完成了#34; (所以我可以避免调用Swing方法),或者阻止Ctrl-C上通常关闭所有窗口的行为?
只是为了澄清:
我在名为stop()
的类中有一个方法。在正常情况下,这可以被调用(连同其补充start()
)并且它会触发导致JLabel更新的级联事件,以获得stop()
已发生的视觉反馈。
当我的关闭钩子运行时,我需要调用stop()
来优雅地关闭一些资源。
我问的是如何检测到Swing EDT不存在,所以我可以重写stop()
以便检测到缺少Swing并避免调用Swing函数。
答案 0 :(得分:3)
以下hack有助于确定JVM是否正在关闭而不传递任何标志:
private static final Thread DUMMY_HOOK = new Thread();
public static boolean isShuttingDown()
{
try {
Runtime.getRuntime().addShutdownHook(DUMMY_HOOK);
Runtime.getRuntime().removeShutdownHook(DUMMY_HOOK);
} catch ( IllegalStateException e ) {
return true;
}
return false;
}
但请不要忘记可能的并发问题。
答案 1 :(得分:2)
关闭挂钩不应期望其他服务处于已知状态(例如UI事件处理线程等),因为已请求关闭应用程序。编写一个试图更新钩子控件内不是100%的东西的关闭钩子可能会导致这个以及其他很难排除故障的行为。
addShutdownHook
方法专门提到了这种情况,并警告您不应该尝试这些类型的操作,因为这样做很容易导致意外后果,例如您观察到的锁定。
关闭挂钩在虚拟生命周期的微妙时间运行 机器,因此应该进行防御性编码。他们应该在 特别是,写成线程安全并避免死锁 尽可能的。他们也不应盲目依赖服务 可能已经注册了自己的关机钩子,因此可能 他们自己正在关闭。
在这种情况下,由于Swing是一个您无法控制的多线程UI系统,我建议您不要在程序生命周期的关闭阶段尝试更改UI中的任何内容。这样做会导致奇怪的,不可预测的,有时不可重复的情况,从一次运行到另一次运行,或者从一台机器到另一台机器,可能会有所不同,具体取决于线程如何安排关闭。另一个线程如何以及何时停止其工作并非旨在以线性,可预测的方式发生。因此,您在多线程程序中编写的任何代码依赖于另一个线程在某个特定时间处于特定状态(除非这些线程明确地相互通信关于其状态),这将打开您的这些类型的问题。
我想我的后续问题是,“为什么你想要/需要在关机过程中改变JLabel?”如果你想在关机前更改某些内容的状态,那么更好的方法就是将键盘输入作为常规事件捕获(防止它导致应用程序关闭),更改JLabel文本,然后通过致电System.runFinalization()和/或System.ext(int)开始关闭应用程序
答案 2 :(得分:0)
我最终在关闭钩子的开头设置了一个标志,并通过我的stop()
方法将这个(通过提前设置的对象)传递给对象,以便它可以测试这个标志并决定是否调用Swing方法。
如果未设置shutdown标志,则调用Swing方法。否则他们不会。