Перейти к основному содержимому

Runtime.getRuntime().halt() против System.exit() в Java

· 4 мин. чтения

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 .