Как использовать качание в хуке выключения?

Есть ли какой-либо способ добавить свинг в хук выключения (то есть отображать всплывающее окно при выключении виртуальной машины)?

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


person Alex Coleman    schedule 25.08.2012    source источник
comment
Я бы сказал, что нет, и даже если бы вы могли, я бы порекомендовал вам этого не делать.   -  person MadProgrammer    schedule 25.08.2012
comment
@MadProgrammer Я огляделся и ничего не нашел, но я думал, что это должно быть возможно, поскольку многие приложения выводят всплывающее окно не только при закрытии, но и при выключении компьютера (что, в свою очередь, выключает Java виртуальная машина)   -  person Alex Coleman    schedule 25.08.2012
comment
Недавно у меня была программа, выбрасывающая исключение, потому что разработчик обращался к компоненту Swing в хуке выключения (я думаю, в Java 7). Я бы сказал, что у вас могут возникнуть проблемы с попыткой следовать этой концепции. Часть проблемы заключается в том, что вы не знаете, в каком состоянии на самом деле находится JVM или в каком порядке вызываются перехватчики выключения.   -  person MadProgrammer    schedule 25.08.2012
comment
@AlexColeman Конечно, можно отобразить всплывающее окно, но не с помощью крючка выключения, как вы, кажется, предполагаете. Обычно это делается в событии закрытия окна.   -  person user207421    schedule 26.08.2012
comment
На Macintosh у вас может быть ApplicationListener с методом public void handleQuit(ApplicationEvent). Если вы хотите поддерживать/иметь машину с Windows, это не сработает, потому что она находится в пакете com.apple.   -  person 11684    schedule 27.08.2012


Ответы (5)


Тебе действительно не следует этого делать. Из спецификации Runtime.addShutdownHook :

Виртуальная машина Java выключается в ответ на два типа событий:

  • Программа завершается в обычном режиме, когда завершается последний поток, не являющийся демоном, или когда вызывается метод exit (эквивалентно System.exit), или
  • Виртуальная машина завершается в ответ на прерывание пользователя, например ввод ^C, или общесистемное событие, такое как выход пользователя из системы или завершение работы системы.

...

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

Отключающие хуки также должны быстро заканчивать свою работу. Когда программа вызывает exit, ожидается, что виртуальная машина быстро выключится и выйдет. Когда виртуальная машина завершает работу из-за выхода пользователя из системы или завершения работы системы, базовая операционная система может разрешить только фиксированное количество времени для завершения работы и выхода. Поэтому не рекомендуется пытаться взаимодействовать с пользователем или выполнять длительные вычисления в обработчике выключения.

...

В редких случаях виртуальная машина может прервать, то есть перестать работать без корректного завершения работы. Это происходит, когда виртуальная машина завершается извне, например сигналом SIGKILL в Unix или вызовом TerminateProcess в Microsoft Windows. Виртуальная машина также может прервать работу, если собственный метод пойдет не так, например, из-за повреждения внутренних структур данных или попытки доступа к несуществующей памяти. Если виртуальная машина аварийно завершает работу, то нельзя гарантировать, будут ли запущены какие-либо перехватчики выключения.

Конкретные предупреждения, которые предлагают вам не делать это:

  1. "Перехватчики завершения работы также должны быстро завершать свою работу".

    Полагаться на что-либо, выполнение работы которого может занять некоторое время, или блокировать на неопределенный срок пользовательский ввод, например JOptionPane диалогов, — это не то, что вам следует делать в обработчике выключения.

  2. "Попытки использовать другие службы на основе потоков, такие как, например, поток отправки событий AWT, могут привести к взаимоблокировкам"

    Swing работает поверх AWT, чей базовый поток отправки событий также может быть в процессе закрытия. Попытка использовать Swing или AWT во время выключения может привести не только к мертвым блокировкам, но и в любом случае может просто не работать.

  3. "Если виртуальная машина аварийно завершает работу, нельзя гарантировать, будут ли запущены какие-либо перехватчики завершения работы"

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

person obataku    schedule 25.08.2012
comment
Это то, что я понял раньше, надеялся, что будет способ, но я полагаю, что нет. - person Alex Coleman; 25.08.2012

Крюки выключения должны выполняться как можно быстрее. Это не включает ожидание подтверждения диалога пользователем. В любом случае у вас нет гарантии, что поток событий Swing все еще работает.

Вы не можете этого сделать.

person user207421    schedule 25.08.2012
comment
+1 хорошо, что у вас нет гарантии, что поток событий Swing все еще работает - person David Kroukamp; 25.08.2012

Если он есть, он вам не поможет.

Перехватчики выключения вызываются асинхронно как часть выключения JVM, поэтому диалоговое окно «подтвердить» на самом деле ничего не подтвердит, поскольку вы не можете остановить или отменить процесс выключения. Ожидание решения пользователя — это не то действие, для которого предназначен хук выключения. Хук выключения в интерактивной программе не имеет смысла. Реальный вариант использования перехватчиков выключения:

для освобождения ресурсов и других хозяйственных операций при завершении работы JVM.

Также важно отметить, что хук выключения не всегда будет запускаться, подробнее см. мой ответ здесь: Как правильно закрыть Java-приложение из C# one

person David Kroukamp    schedule 25.08.2012
comment
Несмотря на то, что он обрабатывается асинхронно, поток по-прежнему не является демоном и, следовательно, может работать... не то, чтобы вам когда-либо приходилось это делать. - person obataku; 25.08.2012
comment
@veer правда, но я думаю, что самая большая проблема, с которой столкнется OP, заключается в том, что не все завершения приложения будут вызывать хук выключения. - person David Kroukamp; 25.08.2012

  1. Графический интерфейс Swing должен быть выполнен в потоке отправки событий, затем

  2. Простой способ, но требующий действий конечного пользователя (закрыть JDialog)

person mKorbel    schedule 25.08.2012
comment
Боюсь, я не понимаю, какое отношение ваш ответ имеет к исходному вопросу. - person Duncan Jones; 25.08.2012
comment
@DuncanJones Он отвечает. Его ответ о хуке выключения + ссылки на возможное решение... - person Alex Coleman; 25.08.2012
comment
@mKorbel Я не понимаю, как сработает первый вариант; Я не призываю к хуку выключения, это происходит как случайное событие, я просто хочу обработать его с помощью всплывающего окна. Во-вторых, я вижу некоторый потенциал в том, однако, будет ли работать Runtime#exec, когда JVM/компьютер выключается? - person Alex Coleman; 25.08.2012
comment
@Alex Coleman Runtime#exec - это один из семи вариантов, если есть что-то, чего вы не понимаете, то ищите вопрос о JVM, Swing и почему Shutdown Hook не работает для графического интерфейса Swing с фоновыми задачами. - person mKorbel; 25.08.2012

Я не уверен в вашем вопросе, но я думаю, что невозможно запустить или отобразить всплывающее окно, когда JVM закрывается. Это как пытаться бежать, готовясь ко сну? Просто угадаю. :)

person user1577161    schedule 25.08.2012