Статьи

Выключение приложения с графическим интерфейсом Java

В последнее время у меня были проблемы с одним или двумя приложениями 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 .