Reputation: 2876
What happens when the JVM is terminated with System.exit(0)
or ^C
or anything of that kind? I read things like "the process is just blown away" and "every single thread is stopped", but I would like to know what happens exactly. I already know there is the shutdownHook
that somehow still gets executed, but what happens before the shutdownHooks are invoked and does anything happen after all these threads have finished?
I would like to implement such a shutdownHook
correctly and to do so I need to make the right assumptions about what might still be executed and what will not.
some code:
class SomeObject {
private boolean stopped;
SomeObject() {
stopped = false;
Thread hook = new Thread() {
@Override
public void run() {
stopped = true;
}
};
hook.setPriority(Thread.MAX_PRIORITY);
Runtime.getRuntime().addShutdownHook(hook);
}
boolean map(Iterator<Object> it) {
while(it.hasNext() && !stopped) {
writeToOtherObject(it.next());
it.remove();
}
//have calculations finished?
return !it.hasNext();
}
}
The map
function computes results that are gathered in some other object. This object should be stored in some file before everything is broken down (by normal-priority shutdownHook
s too). Does the shutdownHook
here make sense? As far I understand it, all threads are destroyed first and only then the shutdownHook
s are run (concurrently, but I assume high-priority threads are run first...) and then objects are finalized. This makes the code above rather useless, because the intention of this shutdownHook
would be to make sure no new loop is started when the shutdown has already started. Is my understanding correct and complete?
Upvotes: 20
Views: 8211
Reputation: 34618
Let's begin from the different ways the shutdown sequence can be initiated:
System.exit()
or Runtime.exit()
.When System.exit(int)
is called, it calls Runtime.exit()
. It checks with the security manager whether it is permitted to exit with the given status, and if so, calls Shutdown.exit()
.
If you interrupted the JVM or the system sent it the TERM signal, then by default, Shutdown.exit()
is called directly without checking with the security manager.
The Shutdown
class is an internal, package-private class in java.lang
. It has, among others, an exit()
and a halt()
methods. Its exit()
method does some stuff to prevent the hooks from being executed twice, and so on, but basically, what it does is
join
for each of them at the end. Other system hooks may run before or after the application hooks.runFinalizersOnExit
anyway.Now, contrary to your supposition, it is at stage 3 that all the threads are stopped. The halt
method is native, and I have not attempted to read the native code, but up to the moment it is called, the only code being ran is pure Java, and there is nothing that stops the threads anywhere in it. The documentation of Runtime.addShutdownHook
says, in fact:
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)
So you see, it is indeed part of the shutdown hook's job to tell threads that they should leave their loops and clean up.
Another misconception you have is about giving the thread a high priority. A high priority doesn't mean that the thread will run first, before all other hooks. It merely means that whenever the operating system has to make a decision which of the threads which are in "ready to run" state to give to a CPU to run, a high-priority thread will have a higher probability of "winning" - depending on the operating system's scheduling algorithm. In short, it may get a little more CPU access, but it will not - especially if you have more than one CPU core - necessarily start before other threads or complete before them.
One last thing - if you want to use a flag to tell a thread to stop working, that flag should be volatile
.
Upvotes: 15
Reputation: 3151
Take a look at this article from DZone. It covers the JVM and its termination in sufficient detail, with a focus on the use of ShutdownHook
.
From a high level, some of the important assumptions it covers include:
- Shutdown Hooks may not be executed in some cases!
- Once started, Shutdown Hooks can be forcibly stopped before completion.
- You can have more than one Shutdown Hook, but their execution order is not guaranteed.
- You cannot register / unregister Shutdown Hooks with in Shutdown Hooks
- Once shutdown sequence starts, it can be stopped by Runtime.halt() only.
- Using shutdown hooks require security permissions.
- Exceptions thrown by the Shutdown Hooks are treated same as exceptions thrown by any other code segment.
Upvotes: 3