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