3

对于属于 class 的关闭钩子是Thread在调用关闭的线程上运行它们的可运行代码还是在它们自己上运行,存在一些冲突。

addShutdownHook将 aThread作为参数。这意味着线程将启动并run自行运行其方法。这也与以下文档一致addShutdownHook

公共无效 addShutdownHook(线程挂钩)

注册一个新的虚拟机关闭挂钩。Java 虚拟机关闭以响应两种事件:

  • 程序正常退出,当最后一个非守护线程退出或调用 exit(等效于 System.exit)方法时,或
  • 虚拟机响应用户中断(例如键入 ^C)或系统范围的事件(例如用户注销或系统关闭)而终止。

关闭挂钩只是一个已初始化但未启动的线程。当虚拟机开始其关闭序列时,它将以某种未指定的顺序启动所有已注册的关闭挂钩并让它们同时运行。当所有钩子都完成后,如果 finalization-on-exit 已启用,它将运行所有未调用的终结器。最后,虚拟机将停止。请注意,在关闭序列期间,守护线程将继续运行,如果通过调用 exit 方法启动关闭,非守护线程也将继续运行。

(强调我的)

但是,代码如下

/* 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代码。该代码不会启动线程(在 a 的情况下,假设在线程上运行Thread是自然且正确的。)run

所以这里确实有问题。是 Javadoc 和addShutdownHook方法的签名,每个代码应该采用线程,而是可运行?是执行吗?还是更有可能是罪魁祸首——我;如果是这样,如何?

4

1 回答 1

4

你很困惑Shutdown.runHooks()ApplicationShutdownHooks.runHooks()。您注册的关闭挂钩Runtime已注册到ApplicationShutdownHooks,它本身将 a 注册RunnableShutdown挂钩

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).

public void addShutdownHook(Thread hook) {
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        sm.checkPermission(new RuntimePermission("shutdownHooks"));
    }
    ApplicationShutdownHooks.add(hook);
}
于 2013-10-23T19:24:09.463 回答