对于Thread类的shutdown挂钩是否在调用shutdown的线程上运行其可运行代码还是自行运行,存在一些冲突。

addShutdownHookThread作为参数。这意味着线程将自行启动并运行其run方法。这也与addShutdownHookdocumentation一致:


  公共无效addShutdownHook(线程钩)
  
  注册一个新的虚拟机关闭挂钩。
  Java虚拟机将响应以下两种事件而关闭:
  
  
  当最后一个非守护线程退出时,或者调用exit(等效于System.exit)方法时,程序将正常退出,或者
  响应于用户中断(例如键入^ C)或系统范围的事件(例如用户注销或系统关闭)来终止虚拟机。
  
  
  关闭钩子只是一个已初始化但未启动的线程。当虚拟机开始其关闭序列时,它将以未指定的顺序启动所有已注册的关闭挂钩,并使其同时运行。当所有挂钩完成后,如果启用了退出时终结,则它将运行所有未调用的终结器。最后,虚拟机将停止。请注意,如果关闭是通过调用exit方法启动的,则守护程序线程将在关闭序列期间继续运行,非守护程序线程也将继续运行。


(强调我的)

但是,代码为as follows

/* 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中的little changed,这使问题更加清楚了:

/* 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方法的签名,每个代码不应该占用线程,而是可以运行吗?是实施吗?还是更可能的罪魁祸首-我?如果是这样,怎么办?

最佳答案

您混淆了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) { }
    }
}


作为参考,Runtime#addShutdownHook(Thread)的(oracle jdk7)代码。

public void addShutdownHook(Thread hook) {
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        sm.checkPermission(new RuntimePermission("shutdownHooks"));
    }
    ApplicationShutdownHooks.add(hook);
}

10-08 14:01