Я использую лицензированный API, у которого есть метод получения/освобождения объекта лицензии с сервера лицензий, который имеет конечное количество лицензий. В начале моего приложения я вызываю метод для получения лицензии, но я хочу убедиться, что он будет выпущен, даже если моя программа внезапно завершится/вылетит (исключения, SIGTERM и т. д.). Является ли крюк выключения лучшим способом решить эту проблему?
Как обеспечить выполнение фрагмента кода перед выходом из Java-приложения
Ответы (4)
@thedan прав насчет жестких сбоев JVM. Если JVM сильно выйдет из строя или получит SIGKILL, у нее не будет возможности запустить что-либо до выхода. Вы ничего не можете сделать, чтобы исправить это в Java в этом сценарии. (Но такая же ситуация и в других языках...)
Однако, если JVM выполняет упорядоченное завершение работы в ответ на завершение всех потоков, отличных от dameon, вызов System.exit(), получение SIGINT и т. д., то JVM попытается запустить перехватчики выключения. Дополнительную информацию о механизмах перехватчиков завершения работы Java см. в разделе Вопросы и ответы. и javadocs .
Подход finally
также является вариантом, но он работает только в том случае, если рассматриваемый поток завершается до выхода из JVM. Этого не произойдет, если вызывается System.exit()
или JVM завершается сигналом. Хуки выключения работают в большем количестве ситуаций.
(На мой взгляд, finally
действительно предназначен для выполнения очистки в одном потоке, а не во всем приложении. Однако, если ваше приложение состоит только из одного потока... или если у него есть главный поток, который отвечает за упорядоченное завершение работы... тогда finally
может служить для очистки приложения.)
Реальное решение состоит в том, чтобы настроить лицензированный API так, чтобы менеджер лицензий мог определить, когда экземпляр приложения, использующий лицензию, исчезает, не освобождая его. Возможно ли это, зависит от менеджера лицензий.
Если программа завершается из-за сбоя JVM, вы не можете полагаться на то, что что-либо вызывается.
Если программа завершается из-за исключения, которое не связано с JVM, вы должны иметь возможность обернуть все в блок try/catch/finally. Любой код в блоке finally будет гарантированно запущен до выхода вашего кода.
Для исключений вы можете обернуть тело main
в файл try/catch/block
. Для обработки сигнала SIGTERM
вы можете добавьте перехватчик выключения. Однако не гарантируется, что хук выключения сработает для такого сигнала, как SIGKILL
.
В редких случаях виртуальная машина может прервать работу, то есть перестать работать, не завершив работу корректно. Это происходит, когда виртуальная машина завершается извне, например сигналом
SIGKILL
в Unix или вызовомTerminateProcess
в Microsoft Windows. Виртуальная машина также может прервать работу, если собственный метод пойдет не так, например, из-за повреждения внутренних структур данных или попытки доступа к несуществующей памяти. Если виртуальная машина аварийно завершает работу, нельзя гарантировать, будут ли запущены какие-либо перехватчики завершения работы.
вы достигаете этого, никогда не вызывая System.exit(). В main() вы создаете «последнюю линию защиты» с помощью
try {
startApp();
} catch (Exception ex) {
// do some logging
} finally {
releaseLicense();
}
finally
? - person Paul Vargas   schedule 07.12.2012