What happens when the JVM is terminated?

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:

  1. Shutdown Hooks may not be executed in some cases!
  2. Once started, Shutdown Hooks can be forcibly stopped before completion.
  3. You can have more than one Shutdown Hook, but their execution order is not guaranteed.
  4. You cannot register / unregister Shutdown Hooks with in Shutdown Hooks
  5. Once shutdown sequence starts, it can be stopped by Runtime.halt() only.
  6. Using shutdown hooks require security permissions.
  7. Exceptions thrown by the Shutdown Hooks are treated same as exceptions thrown by any other code segment.

Let's begin from the different ways the shutdown sequence can be initiated:

  • The last non-daemon thread ends.
  • The JVM is interrupted (by using ctrlC or sending SIGINT).
  • The JVM is terminated (by sending SIGTERM)
  • One of the threads calls 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

  1. Run the System Hooks. The System Hooks are registered internally by JRE methods. They are ran sequentially, not in threads. The second system hook is what runs the application hooks that you have added. It starts each of them as a thread and then has a join for each of them at the end. Other system hooks may run before or after the application hooks.
  2. If finalizers are supposed to be ran prior to halting, they are ran. This should generally not even happen, as the method has been deprecated. And if the exit is with a status other than zero, it ignores the runFinalizersOnExit anyway.
  3. The JVM is halted.

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.

Tags:

Java

Shutdown

Jvm