Почему официальная документация 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);
}
Другие вопросы по тегам