javaagent, системный лоток и выключение

Мы пишем java-агент, который, среди прочего, предоставляет какой-то графический интерфейс с использованием java.awt.TrayIcon. Когда мы используем этот агент, например, Tomcat, у нас возникла следующая проблема:

  1. Пользователь запускает Tomcat с помощью сценария оболочки
  2. Наш агент добавляет значок на панель задач
  3. Пользователь выключает Tomcat с помощью сценария оболочки
  4. AWT Event thread видит, что есть отображаемый компонент, значок в панели задач, и не закрывается.
  5. Поскольку поток событий AWT не является потоком демона, все приложение не может завершить работу

Теперь вопрос в том, что нам делать, чтобы приложение завершило работу? Можно ли сделать демон потока отправки событий AWT? Есть ли крючки выключения для агентов? Что-нибудь еще?


person Nikem    schedule 26.03.2012    source источник


Ответы (2)


Для полноты картины вот как я решил эту проблему:

Я запустил еще один поток демона с заданием, который периодически проверяет отображаемые компоненты AWT. Если остался только один из них, и это мой значок в панели задач, я удаляю его. Это позволяет подсистеме AWT выйти, что приведет к нормальному завершению работы всего приложения.

person Nikem    schedule 19.12.2012

Вы можете попробовать добавить ловушку выключения (Runtime.getRuntime().addShutdownHook()), которая вызывает

SystemTray.getSystemTray( ).remove( trayIcon );

person Bruno Grieder    schedule 26.03.2012
comment
К сожалению, ловушка выключения никогда не вызывается, поскольку фактически JVM не завершает работу. Именно поток событий AWT заставляет его продолжать работу. - person Nikem; 26.03.2012
comment
На какой ОС вы работаете? На * ix SIGTERM запускает ловушку (-ы) завершения, а SIGKILL принудительно завершает JVM, несмотря на то, что какой-либо поток, не являющийся запущенным демоном. - person Bruno Grieder; 26.03.2012
comment
Да, но я не говорю о принудительном завершении работы JVM. Проблема в том, как позволить JVM завершиться естественным образом при выходе из основного метода. Поскольку ловушка выключения не вызывается, когда основные методы завершаются, но все еще выполняются потоки, не являющиеся демонами. - person Nikem; 26.03.2012
comment
Тогда почему бы просто не удалить ваши ресурсы AWT (например, SystemTray.getSystemTray( ).remove( trayIcon ); в конце основного метода. Кстати, перехватчики выключения вызываются, когда JVM выходит нормально - person Bruno Grieder; 26.03.2012
comment
1. Пожалуйста, перечитайте мой вопрос. Основной метод приложения полностью вне моего контроля. Пишу java-агент. - person Nikem; 26.03.2012
comment
2. Если основной метод завершается, это не всегда означает, что приложение закрывается. Метод main может запускать другие рабочие потоки, не являющиеся демонами. Так что удаление значка в системном трее во время работы приложения - это не то, чего я хотел бы :( - person Nikem; 26.03.2012
comment
И еще раз. ловушки выключения запускаются ПОСЛЕ того, как все потоки, не являющиеся демонами, перестают существовать. В моем случае выполняется поток событий AWT, поэтому перехватчики выключения не выполняются. - person Nikem; 26.03.2012
comment
Плохо, я пропустил тот факт, что это Java-агент - person Bruno Grieder; 26.03.2012
comment
Последняя попытка. Можете ли вы обернуть ваше приложение / tomcat оболочкой Java Service Wrapper? Затем вы можете вызвать WrapperManager.signalStopping() из Java для запуска сценария kill на Wrapper. Вот как мы это делаем, но, честно говоря, наш лоток загружается не из Java-агента. - person Bruno Grieder; 26.03.2012
comment
Вы можете прослушивать события в WrapperManager; не уверен, что это будет работать с java-агентом, но обычно обнаруживается убийство. - person Bruno Grieder; 26.03.2012