В последнее время у меня были проблемы с одним или двумя приложениями 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() { @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(); |
Теперь вы заметите, что поток возвращается, если он прерывается, а также он запускается как поток 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() { @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 из вспомогательного потока с частотой менее секунды, если только вы не прервете поток, если компонент, который он обновляет, больше не виден!
Как примечание после того, как я обнаружил проблему, я нашел это очень
Ссылка: Завершение работы приложения Java с графическим интерфейсом Получите от нашего партнера по JCG Стива Уэбба на Java Desktop Development в блоге Coal Face .