对于Thread
类的shutdown挂钩是否在调用shutdown的线程上运行其可运行代码还是自行运行,存在一些冲突。addShutdownHook
将Thread
作为参数。这意味着线程将自行启动并运行其run
方法。这也与addShutdownHook
的documentation一致:
公共无效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);
}