There's a bit of a clash for whether shutdown hooks, which are of class Thread
, run their runnable code on the thread on which the shutdown was called, or run on themselves.
addShutdownHook
takes a Thread
as a parameter. This implies the thread will start and run its run
method on itself. This is also consistent with the documentation for addShutdownHook
:
public void addShutdownHook(Thread hook)
Registers a new virtual-machine shutdown hook. The Java virtual machine shuts down in response to two kinds of events:
- The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
- The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.
A shutdown hook is simply an initialized but unstarted thread. When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently. When all the hooks have finished it will then run all uninvoked finalizers if finalization-on-exit has been enabled. Finally, the virtual machine will halt. Note that daemon threads will continue to run during the shutdown sequence, as will non-daemon threads if shutdown was initiated by invoking the exit method.
(Emphasis mine)
However, the code is 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;
}
}
}
}
(!!
comment mine)
Note this is little changed from JDK 6, which makes the problem all the clearer:
/* 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;
}
}
}
}
At first I thought I was reading this wrong and calling run
magically started the thread. But it doesn't. I wrote the run
code myself. That code does not start a thread (in the case of a Thread
, it's natural and correct to assume run
runs on the thread.)
So something is really wrong here. Is it the Javadoc and the signature of the addShutdownHook
method, which per the code should not be taking a thread, but a runnable? Is it the implementation? Or is it the more likely culprit - me; and if so, how?
You are confusing
Shutdown.runHooks()
andApplicationShutdownHooks.runHooks()
. The shutdown hooks you register withRuntime
are registered withApplicationShutdownHooks
, which itself registers aRunnable
as aShutdown
hookThe shutdown hooks are ran concurrently
For reference, the (oracle jdk7) code for
Runtime#addShutdownHook(Thread)
.