1. Обзор
В этом руководстве мы рассмотрим System.exit()
, Runtime.getRuntime().halt()
и сравнение этих двух методов друг с другом.
2. Система.выход()
Метод System.exit()
останавливает работающую виртуальную машину Java . Но перед остановкой JVM вызывается последовательность выключения , также известная как упорядоченное выключение. Пожалуйста , обратитесь к этой статье , чтобы узнать больше о добавлении перехватчиков выключения.
Последовательность выключения JVM сначала вызывает все зарегистрированные перехватчики выключения и ожидает их завершения. Затем он запускает все незадействованные финализаторы, если включена финализация при выходе
. Наконец, он останавливает JVM.
Этот метод фактически вызывает метод Runtime.getRuntime().exit()
внутри. Он принимает целочисленный код состояния в качестве аргумента и имеет возвращаемый тип void :
public static void exit(int status)
Если код состояния не равен нулю, это означает, что программа остановилась аварийно.
3. Время выполнения.getRuntime().halt()
Класс Runtime
позволяет приложению взаимодействовать со средой, в которой оно работает.
У него есть метод остановки
, который можно использовать для принудительного завершения работающей JVM .
В отличие от метода выхода
, этот метод не запускает последовательность завершения работы JVM. Поэтому ни перехватчики выключения, ни финализаторы не выполняются, когда мы вызываем метод halt
.
Этот метод нестатичен и имеет сигнатуру, аналогичную System.exit()
:
public void halt(int status)
Подобно выходу
, ненулевой код состояния в этом методе также указывает на аварийное завершение программы.
4. Пример
Теперь давайте посмотрим на пример методов выхода
и остановки
с помощью перехватчика выключения.
Для простоты мы создадим класс Java и зарегистрируем перехватчик выключения в статическом
блоке. Также мы создадим два метода; первый вызывает метод выхода
, а второй вызывает метод остановки
:
public class JvmExitAndHaltDemo {
private static Logger LOGGER = LoggerFactory.getLogger(JvmExitAndHaltDemo.class);
static {
Runtime.getRuntime()
.addShutdownHook(new Thread(() -> {
LOGGER.info("Shutdown hook initiated.");
}));
}
public void processAndExit() {
process();
LOGGER.info("Calling System.exit().");
System.exit(0);
}
public void processAndHalt() {
process();
LOGGER.info("Calling Runtime.getRuntime().halt().");
Runtime.getRuntime().halt(0);
}
private void process() {
LOGGER.info("Process started.");
}
}
Итак, чтобы сначала протестировать метод выхода, давайте создадим тестовый пример:
@Test
public void givenProcessComplete_whenExitCalled_thenTriggerShutdownHook() {
jvmExitAndHaltDemo.processAndExit();
}
Давайте теперь запустим тестовый пример и увидим, что хук выключения вызывается:
12:48:43.156 [main] INFO com.foreach.exitvshalt.JvmExitAndHaltDemo - Process started.
12:48:43.159 [main] INFO com.foreach.exitvshalt.JvmExitAndHaltDemo - Calling System.exit().
12:48:43.160 [Thread-0] INFO com.foreach.exitvshalt.JvmExitAndHaltDemo - Shutdown hook initiated.
Точно так же мы создадим тестовый пример для метода halt :
@Test
public void givenProcessComplete_whenHaltCalled_thenDoNotTriggerShutdownHook() {
jvmExitAndHaltDemo.processAndHalt();
}
Теперь мы также можем запустить этот тестовый пример и увидеть, что хук выключения не вызывается:
12:49:16.839 [main] INFO com.foreach.exitvshalt.JvmExitAndHaltDemo - Process started.
12:49:16.842 [main] INFO com.foreach.exitvshalt.JvmExitAndHaltDemo - Calling Runtime.getRuntime().halt().
5. Когда использовать выход
и остановку
Как мы видели ранее, метод System.exit()
запускает последовательность завершения работы JVM, тогда как метод Runtime.getRuntime().halt()
резко завершает работу JVM.
Мы также можем сделать это с помощью команд операционной системы. Например, мы можем использовать SIGINT или Ctrl+C, чтобы инициировать упорядоченное завершение работы, такое как System.exit()
и SIGKILL, чтобы внезапно завершить процесс JVM.
Поэтому нам редко приходится использовать эти методы. Сказав это, нам может понадобиться использовать метод выхода
, когда нам нужно, чтобы JVM запускала зарегистрированные перехватчики завершения работы или возвращала вызывающей стороне определенный код состояния, например, в сценарии оболочки.
Однако важно отметить, что хук выключения может привести к взаимоблокировке, если он не спроектирован должным образом. Следовательно, метод выхода
может быть заблокирован , поскольку он ожидает завершения работы зарегистрированных перехватчиков выключения. Таким образом, возможный способ позаботиться об этом - использовать метод остановки
, чтобы заставить JVM останавливаться в случае блокировки выхода .
Наконец, приложение также может ограничить случайное использование этих методов. Оба эти метода вызывают метод checkExit класса
SecurityManager
. Таким образом, чтобы запретить операции выхода
и остановки
, приложение может создать политику безопасности с помощью класса SecurityManager и сгенерировать исключение
SecurityException
из метода checkExit
.
6. Заключение
В этом руководстве мы рассмотрели методы System.exit()
и Runtime.getRuntime().halt()
на примере. Кроме того, мы также говорили об использовании и лучших практиках этих методов.
Как обычно, полный исходный код этой статьи доступен на Github .