最近,我遇到了一个或两个Java GUI应用程序在关闭时无法关闭的问题。
它们似乎是一个过程,消耗着计算机资源。
今天,我深入探究了问题的根源,这是一个我以前从未意识到的棘手问题,所以我想我会分享一下。
理论上,当您关闭Java应用程序时,应停止所有线程,并且进程应终止。
就我而言,当我监视应用程序时,我希望完成的线程(例如Swing工作池)仍然处于活动状态,即Strange。
原因是AWT Shutdown线程没有终止所有帮助程序线程,原因是EventQueues中仍然存在AWT事件。
我将解释其原因是真正的偷偷摸摸的小gatcha。
我的应用程序使用了一个具有常规睡眠的线程,但是当醒来时会进行一些计算,然后调用以更新gui:
Thread updateThread = new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
do {
try {
Thread.sleep(300); // 300ms
gui.updateValue(SOME_VALUE)
} catch(InterruptException ex) {
return;
}
frame.setValue(SOMEDATA);
} while(i++ < 100);
}
}, "updateThread");
updateThread.setDaemon(true);
updateThread.start();
现在您将注意到,如果线程被中断并且作为守护程序线程启动,则该线程返回。
我曾以为,作为应用程序关闭的一部分,线程将终止,但实际上不是。
这是由gui.updateValue(SOME_VALUE)使用InvokeLater引起的:
public void updateValue(final int value) {
// make sure we access graphics in the EDT thread
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
...
...
...
SOME CODE
}catch(Exception t) {
// not a lot to do
}
}
});
}
InvokeLater基本上是在EventQueue上放置一个事件,因此AWT Shutdown线程想要关闭应用程序。
AWT Shutdown线程每秒钟检查一次EventQueues,但是正如您将看到的,我的Thread会执行更新一秒(300ms),因此队列上始终有一个事件!
简而言之,AWT Shutdown线程永远不会终止我希望其终止的线程,因此需要终止应用程序。
在我的线程的while循环中,变通方法很简单,我还检查了通过它进行更新的JComonent是否仍然可见并显示,如果不是退出循环,则该线程死亡,因此没有其他事件放在事件线程上,应用程序按预期关闭:)
Thread updateThread = new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
do {
try {
Thread.sleep(300); // 300ms
gui.updateValue(SOME_VALUE);
}catch(InterruptException ex) {
return;
}
frame.setValue(SOMEDATA);
}while(i < 100 && progressGlassPane.isVisible() && progressGlassPane.isShowing());
}
}, "updateThread");
updateThread.setDaemon(true);
updateThread.start();
因此,简而言之,不要以低于一秒的频率从帮助程序线程中调用InvokeLater,除非在正在更新的组件不再可见的情况下也终止了该线程!
作为旁注,发现问题后,我发现这非常
参考: Coal Face博客上Java桌面开发的 JCG合作伙伴 Steve Webb的Java GUI Application Shutdown Gotcha 。
翻译自: https://www.javacodegeeks.com/2012/05/java-gui-application-shutdown-gotcha.html