Как остановить Swing EDT

Типичное приложение Swing запускает EDT в начале и когда последнее окно закрывается, приложение останавливается в основном с помощью System.exit либо неявным, либо явным.

Но мое небольшое приложение на самом деле является плагином для рамки, которая ничего не знает о Swing. Мой плагин будет при вызове отображать диалог, чтобы получить некоторый ввод от пользователя и выйти потом, но структура будет/должна продолжать работать. Поэтому я не могу назвать System.exit.

Но если я не сделаю этого, EDT продолжит выполнение, и как только структура будет закончена, EDT все равно будет работать и запускаться и запускаться...

Поэтому я бы хотел убить EDT, не убив приложение. Как это сделать?

Ответ 1

Следующий документ от Oracle/Sun пролил свет на проблему: Проблемы с AWT Threading

[...]

До 1.4 вспомогательные потоки никогда не прерывались.

Начиная с 1.4, поведение изменилось в результате исправления для 4030718. В текущей реализации AWT завершает все свои вспомогательные потоки, позволяя приложению выйти чисто, когда выполняются следующие три условия:

  • Нет отображаемых компонентов AWT или Swing.
  • В собственной очереди событий нет встроенных событий.
  • В java EventQueues нет событий AWT.

Поэтому автономное приложение AWT, которое хочет выйти из строя без вызова System.exit, должно:

  • Убедитесь, что все компоненты AWT или Swing не отображаются, когда приложение заканчивается. Это можно сделать, вызвав Window.dispose на всех верхних уровнях Windows. См. Frame.getFrames....
  • Убедитесь, что ни один из методов прослушивателей событий AWT, зарегистрированных приложением с любым компонентом AWT или Swing, не может работать в бесконечном цикле или вешать бесконечно. Например, метод прослушивания AWT, инициированный некоторым событием AWT, может отправлять новое событие AWT того же типа в EventQueue. Аргумент в том, что методы прослушивателей событий AWT обычно выполняются на вспомогательных потоках.

[...]

Ответ 2

Могут быть некоторые скрытые окна (например, диалоги, отображаемые с помощью JOptionPane.showMessageDialog(…), которые уже закрыты), препятствуя выходу Swing. Вы можете проверить это, используя

Stream.of(Window.getWindows()).forEach(System.out::println);

Если вам больше не нужны, вы можете легко избавиться от них:

Stream.of(Window.getWindows()).forEach(Window::dispose);

Диспетчер событий должен останавливаться.