Автор оригинала: Mona Mohamadinia.
1. Обзор
Как правило, запустить сервис очень просто. Однако иногда нам нужен план, как изящно закрыть один из них.
В этом уроке мы рассмотрим различные способы завершения работы приложения JVM. Затем мы будем использовать API Java для управления крючками завершения работы JVM. Пожалуйста, обратитесь к этой статье, чтобы узнать больше о закрытии JVM в приложениях Java.
2. Завершение работы JVM
JVM можно отключить двумя различными способами:
- Контролируемый процесс
- Резким тоном
Контролируемый процесс завершает работу JVM, когда либо:
- Последний не- демон поток завершается. Например, при выходе из основного потока JVM запускает процесс завершения работы
- Отправка сигнала прерывания от операционной системы. Например, нажав Ctrl + C или выйдя из операционной системы
- Вызов System.exit() из кода Java
В то время как мы все стремимся к изящному завершению работы, иногда JVM может завершиться внезапно и неожиданным образом. JVM резко выключается, когда :
- Отправка сигнала об уничтожении из операционной системы. Например, выдав kill -9
- Вызов Runtime.getRuntime().halt() из кода Java
- Хост-ОС неожиданно умирает, например, при сбое питания или панике ОС
3. Выключение Крючков
JVM позволяет регистрировать функции для запуска до завершения завершения работы. Эти функции обычно являются хорошим местом для высвобождения ресурсов или других подобных задач по ведению домашнего хозяйства. В терминологии JVM эти функции называются крючками s shutdown|/.
Крючки выключения в основном инициализированы, но не запущены|/. Когда JVM начнет процесс завершения работы, он запустит все зарегистрированные крючки в неопределенном порядке. После запуска всех крючков JVM остановится.
3.1. Добавление крючков
Чтобы добавить крюк завершения работы, мы можем использовать метод Runtime.getRuntime().addShutdownHook() :
Thread printingHook = new Thread(() -> System.out.println("In the middle of a shutdown")); Runtime.getRuntime().addShutdownHook(printingHook);
Здесь мы просто печатаем что-то на стандартный вывод, прежде чем JVM сама отключится. Если мы закроем JVM следующим образом:
> System.exit(129); In the middle of a shutdown
Затем мы увидим, что крючок действительно выводит сообщение на стандартный вывод.
JVM отвечает за запуск потоков крючков . Поэтому, если данный крючок уже запущен, Java выдаст исключение:
Thread longRunningHook = new Thread(() -> { try { Thread.sleep(300); } catch (InterruptedException ignored) {} }); longRunningHook.start(); assertThatThrownBy(() -> Runtime.getRuntime().addShutdownHook(longRunningHook)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Hook already running");
Очевидно, что мы также не можем зарегистрировать крюк несколько раз:
Thread unfortunateHook = new Thread(() -> {}); Runtime.getRuntime().addShutdownHook(unfortunateHook); assertThatThrownBy(() -> Runtime.getRuntime().addShutdownHook(unfortunateHook)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Hook previously registered");
3.2. Снятие крючков
Java предоставляет метод twin remove для удаления определенного крючка выключения после его регистрации:
Thread willNotRun = new Thread(() -> System.out.println("Won't run!")); Runtime.getRuntime().addShutdownHook(willNotRun); assertThat(Runtime.getRuntime().removeShutdownHook(willNotRun)).isTrue();
Метод removeShutdownHook() возвращает true при успешном удалении крючка выключения.
3.3. Предостережения
JVM запускает крючки выключения только в случае нормального завершения работы. Таким образом, когда внешняя сила внезапно убивает процесс JVM, у JVM не будет возможности выполнить крючки завершения работы. Кроме того, остановка JVM из кода Java также будет иметь тот же эффект:
Thread haltedHook = new Thread(() -> System.out.println("Halted abruptly")); Runtime.getRuntime().addShutdownHook(haltedHook); Runtime.getRuntime().halt(129);
Метод halt принудительно завершает текущую JVM. Таким образом, зарегистрированные крючки завершения работы не получат возможности выполнить.
4. Заключение
В этом уроке мы рассмотрели различные способы завершения работы приложения JVM. Затем мы использовали несколько API среды выполнения для регистрации и снятия с регистрации крючков завершения работы.
Как обычно, пример кода доступен на GitHub .