Почему официальная документация JVM противоречит его реализации в addShutdownHook?
Есть немного столкновения для того, чтобы отключить крючки, которые являются классом Thread
, запустите их исполняемый код в потоке, в котором было вызвано завершение работы, или запустите сами.
addShutdownHook
занимает Thread
в качестве параметра. Это подразумевает, что поток запустится и запустит run
метод на себя. Это также согласуется с документацией для addShutdownHook
:
public void addShutdownHook (Thread hook)
Регистрирует новый хук отключения виртуальной машины. Виртуальная машина Java отключается в ответ на два вида событий:
- Программа завершается нормально, когда завершается последний поток, не являющийся демоном, или когда вызывается метод exit (эквивалентно System.exit), или
- Виртуальная машина прерывается в ответ на пользовательское прерывание, такое как ввод ^C, или общесистемное событие, такое как выход пользователя из системы или завершение работы системы.
Хук отключения - это просто инициализированный, но незапущенный поток. Когда виртуальная машина начинает свою последовательность выключения, она запускает все зарегистрированные обработчики завершения работы в неустановленном порядке и позволяет им запускаться одновременно. Когда все перехватчики завершены, он запустит все непроверенные финализаторы, если финализация при выходе была включена. Наконец, виртуальная машина остановится. Обратите внимание, что потоки демона будут продолжать работать во время последовательности завершения работы, также как и потоки, не являющиеся демонами, если завершение работы было инициировано путем вызова метода выхода.
(Акцент мой)
Тем не менее, код выглядит следующим образом:
/* Run all registered shutdown hooks
*/
private static void runHooks() {
for (int i=0; i < MAX_SYSTEM_HOOKS; i++) {
try {
Runnable hook;
synchronized (lock) {
// acquire the lock to make sure the hook registered during
// shutdown is visible here.
currentRunningHook = i;
hook = hooks[i];
}
if (hook != null) hook.run(); // not Thread.start - Runnable.run (!!)
} catch(Throwable t) {
if (t instanceof ThreadDeath) {
ThreadDeath td = (ThreadDeath)t;
throw td;
}
}
}
}
(!!
комментарий мой)
Обратите внимание, что это немного изменилось по сравнению с JDK 6, что делает проблему более понятной:
/* Run all registered shutdown hooks
*/
private static void runHooks() {
/* We needn't bother acquiring the lock just to read the hooks field,
* since the hooks can't be modified once shutdown is in progress
*/
for (Runnable hook : hooks) {
try {
hook.run();
} catch(Throwable t) {
if (t instanceof ThreadDeath) {
ThreadDeath td = (ThreadDeath)t;
throw td;
}
}
}
}
Сначала я подумал, что неправильно это читаю и звоню run
волшебным образом начал поток. Но это не так. Я написал run
сам код Этот код не запускает поток (в случае Thread
Естественно и правильно предполагать run
работает в потоке.)
Так что здесь что-то не так. Это Javadoc и подпись addShutdownHook
метод, который в коде должен быть не потоком, а работоспособным? Это реализация? Или это более вероятный виновник - я; и если да, то как?
1 ответ
Вы путаете Shutdown.runHooks()
а также ApplicationShutdownHooks.runHooks()
, Крюки отключения, которые вы регистрируете Runtime
зарегистрированы с ApplicationShutdownHooks
, который сам регистрирует Runnable
как Shutdown
крюк
static {
try {
Shutdown.add(1 /* shutdown hook invocation order */,
false /* not registered if shutdown in progress */,
new Runnable() {
public void run() {
runHooks(); // (!!) your hooks
}
}
);
hooks = new IdentityHashMap<>();
} catch (IllegalStateException e) {
// application shutdown hooks cannot be added if
// shutdown is in progress.
hooks = null;
}
}
Крюки отключения запускаются одновременно
static void runHooks() { // In ApplicationShutdownHooks
Collection<Thread> threads;
synchronized(ApplicationShutdownHooks.class) {
threads = hooks.keySet();
hooks = null;
}
for (Thread hook : threads) { // (!!) your hooks
hook.start();
}
for (Thread hook : threads) {
try {
hook.join();
} catch (InterruptedException x) { }
}
}
Для справки, код (oracle jdk7) для Runtime#addShutdownHook(Thread)
,
public void addShutdownHook(Thread hook) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("shutdownHooks"));
}
ApplicationShutdownHooks.add(hook);
}