Выключение крюка против метода финализатора
Я просто не понимаю, почему нужно использовать Runtime.addShutdownHook. Если вы хотите выполнить некоторую очистку при выходе jvm, почему бы не просто перегрузить метод finalize класса daemon. В чем преимущество использования метода завершения выключения при завершении метода.
Также существует устаревшая функция runFinalizersOnExit. Если я установлю его на false, я считаю, что финализаторы не будут работать. Это противоречит гарантии java, что финализаторы всегда запускаются перед сборками мусора.
Ответы
Ответ 1
Нет гарантии, что финализатор будет когда-либо. finalize()
вызывается, когда объект собирает мусор. Но сборщик мусора не может ничего собирать, когда программа работает.
Завершение перехвата заторможенности выполняется, когда jvm завершается нормально. так что даже это не гарантия 100%, но это довольно близко. Есть только несколько краевых случаев, когда не работает затвор завершения.
ИЗМЕНИТЬ
Я посмотрел на гранивые случаи, когда крюк остановки не выполнен.
Завершение выключения выполняется:
- Когда все потоки JVM завершили выполнение
- Из-за вызова System.exit()
- Поскольку пользователь нажимает CNTRL-C
- Выключение системного уровня или выход из системы.
Крюк отключения не выполняется:
- Если VM сбой из-за ошибки в собственном коде, то не может быть никаких гарантий относительно того, будут ли выполняться крючки.
- Если JVM убивается с помощью команды -kill в Linux или Terminate Process на окнах, JVM мгновенно выходит
Ответ 2
Относительно вашего запроса
Если вы хотите выполнить некоторую очистку при выходе jvm, почему бы просто не перегрузить метод finalize класса демона
Я нашел хорошую информацию из этой статьи
-
finalize()
вызывается до того, как сборщик мусора вернет объект. JVM не гарантирует, когда этот метод будет вызван.
-
finalize()
вызывается только один раз по потоку GC, если объект восстанавливается из метода finalize, а finalize больше не будет вызываться.
-
В вашем приложении у вас могут быть живые объекты, на которых никогда не вызывается сборка мусора.
-
Любое исключение генерируется методом finalize игнорируется потоком GC
-
System.runFinalization(true)
и Runtime.getRuntime().runFinalization(true)
методы увеличивают вероятность вызова метода finalize()
, но теперь эти два метода устарели. Эти методы очень опасны из-за отсутствия безопасности потока и возможного создания взаимоблокировки.
Возвращаясь к shutdownHooks, в соответствии с оракулом документация
public void addShutdownHook (Thread hook) Регистрирует новый виджет завершения виртуальной машины.
Виртуальная машина Java отключается в ответ на два вида событий:
- Программа завершается нормально, когда последний поток не-daemon выходит или когда вызывается метод exit (эквивалентно, System.exit) или
- Виртуальная машина завершается в ответ на прерывание пользователя, например, набирает ^ C или общесистемное событие, такое как выход пользователя из системы или выключение системы.
- Когда виртуальная машина начнет свою последовательность выключения, она запустит все зарегистрированные крючки отключения в некотором неуказанном порядке и позволит им запускать одновременно. Когда все крючки закончены, он будет запускать все неинвинированные финализаторы, если финализация на выходе будет включена.
- Наконец, виртуальная машина остановится. Обратите внимание, что потоки демона будут продолжать работать во время последовательности выключения, а также потоки не-демона, если выключение было инициировано вызовом метода exit.
Но даже документация оракула указывала, что
Крюки выключения также должны быстро завершить работу. Когда программа вызывает выход, ожидание состоит в том, что виртуальная машина будет быстро отключена и выйдет.
В редких случаях виртуальная машина может прервать работу, т.е. прекратить работу, не выключаясь полностью
Учитывая недостатки обоих этих подходов, вы должны следовать ниже подхода
-
Не зависеть от finalize()
или shutdown hooks
, чтобы выпустить критические ресурсы в вашем приложении.
-
использовать try{} catch{} finally{}
блокировать соответствующим образом и выпускать критические ресурсы в блоке finally(}
. Во время освобождения ресурсов в блоке finally{}
catch Exception
и Throwable
.