Что произойдет, если System.exit будет вызван из ловушки завершения работы?

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

try {
    return shutdownPromise = doShutdown();
}
catch (Throwable exc) {
    logger.error("An exception was thrown while shutting down the application.", exc);  
    System.exit(1);
    return null;
}

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

Так что я подумал -

  1. Что делает вызов выхода из хука выключения?
  2. Каков правильный способ обработки ошибок от хука выключения?

person djechlin    schedule 23.10.2013    source источник
comment
@libik Почему бы и нет? Это на самом деле поощряется, чтобы делиться знаниями. На самом деле, есть флажок, специально говорящий ответить на ваш собственный вопрос.   -  person tckmn    schedule 24.10.2013
comment
Это хороший ответ; стоит проголосовать.   -  person Bathsheba    schedule 24.10.2013
comment
Ну да, но до тех пор, пока вы действительно задаете вопрос и решаете его сами или с помощью других... Не задавать вопрос и отвечать до того, как кто-то ответит.   -  person libik    schedule 24.10.2013


Ответы (1)


Во-первых, простой ответ: ваш процесс зашел в тупик.

System.exit завершается вызовом Shutdown.exit, который заканчивается этот блок кода:

synchronized (Shutdown.class) {
     /* Synchronize on the class object, causing any other thread
      * that attempts to initiate shutdown to stall indefinitely
      */
     sequence();
     halt(status);
}

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

Перехватчики завершения работы добавляются через ApplicationShutdownHooks.add, как описано в этом ответе здесь. Обратите внимание, что приведенный выше метод sequence в конечном итоге приводит к эта строка кода в Shutdown.runHooks:

if (hook != null) hook.run();

Во-первых, обратите внимание, что эти перехватчики не перехватчики закрытия вашего приложения. Это перехватчики завершения работы системы, которые отличаются друг от друга, и один из них отвечает за обеспечение запуска перехватчиков завершения работы вашего приложения. Обратите внимание, что это run, а не start. Другими словами, он блокирует. Одним из этих обработчиков завершения работы будет системный обработчик, который одновременно запускает все обработчики завершения работы приложения (вы можете проследить этот код для себя или в связанном ответе), а затем блокируется до тех пор, пока все они не завершатся с помощью вызова Thread.join. Одним из них будет хук завершения работы вашего приложения, который, если он вызовет System.exit, будет ожидать блокировки Shutdown.class навсегда.

Далее глупый ответ: звоните Runtime.getRuntime().halt() вместо этого. Я говорю «глупый ответ», потому что это, вероятно, немного более низкий уровень, который вы хотели сделать вместо выхода. Если System.exit представляет чистое завершение работы, которое завершилось ошибкой, то halt — это жесткое завершение работы, которое всегда завершается немедленно.

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

person djechlin    schedule 23.10.2013
comment
Я имел удовольствие узнать это на собственном горьком опыте. Вот пример, если кому интересно: knotgillcup.blogspot.com/ 2019/08/systemexit-not-working.html - person KnotGillCup; 06.08.2019