В последнее время у меня были проблемы с одним или двумя приложениями Java GUI, которые не закрывались при их закрытии. Кажется, они остаются как процесс, потребляя компьютерные ресурсы. Сегодня я понял суть проблемы, и это немного неприятно, о чем я не знал раньше, поэтому я решил поделиться этим.
Теоретически, когда вы закрываете приложение Java, все потоки должны быть остановлены, и процесс должен прекратиться. В моем случае, когда я следил за приложением, потоки, которые я ожидал завершить, такие как рабочие пулы Swing, были еще живы, Стрендж. Причина оказалась в том, что поток завершения работы AWT не завершал все вспомогательные потоки, и причиной этого было то, что в EventQueues все еще были события AWT. Я объясню, что причиной этого является маленький подлый гатча.
Мое приложение использовало поток, который имел нормальный сон, но когда проснулся, потребовались некоторые вычисления, а затем был сделан вызов для обновления графического интерфейса:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
Thread updateThread = new Thread(new Runnable() {@Overridepublic 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(); |
Теперь вы заметите, что поток возвращается, если он прерывается, а также он запускается как поток Daemon. Я думал, что как часть закрытия приложения поток будет прерван, но НЕТ, это не было. Это было вызвано gui.updateValue (SOME_VALUE), использующим InvokeLater:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
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 хочет закрыть приложение. Поток AWT Shutdown проверяет EventQueues каждую секунду, но, как вы увидите, мой поток выполняет обновление за секунду (300 мс), поэтому в очереди всегда есть событие! Короче говоря, поток AWT Shutdown никогда не завершает потоки, которые я хочу завершить, и поэтому приложение должно быть уничтожено.
Обход прост в цикле while моего потока. Я также проверяю, что JComonent, который должен быть обновлен через него, все еще виден и показан, если выход из цикла не завершен, поток умирает, поэтому больше нет событий. поставить на ветку Event и whooohooo приложение закрывается как положено 🙂
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
Thread updateThread = new Thread(new Runnable() {@Overridepublic 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 из вспомогательного потока с частотой менее секунды, если только вы не прервете поток, если компонент, который он обновляет, больше не виден!
Как примечание после того, как я обнаружил проблему, я нашел это очень
Ссылка: Завершение работы приложения Java с графическим интерфейсом Получите от нашего партнера по JCG Стива Уэбба на Java Desktop Development в блоге Coal Face .