1

I have been struggling for a few hours already on that nonsensical problem, so now I'm seeking for help.

1 liner: my shutdown hook is apparently terminated before it finishes its duty.

The code I'm running looks like this:

class Test {

    static {
        Runtime.getRuntime().addShutdownHook(new Thread(Test::shutdown));
    }

    // more methods
    private static void shutdown() {
        Collection<Foo> coll = some.instance.ofHashMap.values();
        System.out.println("collSize=" + coll.size());
        for (Foo o : coll) {
            System.out.println("Calling bar on foo");
            o.bar();
        }
        System.out.println("End of hook");
    }
}

But the output is:

collSize=1

If I run the jvm with the -server option, I might get lucky and the "Calling bar on foo" print but it still doesn't print "End of hook".

Unfortunately, I haven't been able to create a short executable example that shows the problem. I have one but it shows everything's working fine and the collection is iterated as expected. The code above is an extract of a much bigger program i'm working on, but my shut down is hook is doing nothing more than the above (get a non empty collection and iterate).

Any ideas of what might be happening? I am totally lost here...

Notes: - Code is written, compiled and run for/with Java 8u45 - I kill the program with Ctrl+C, as a result, the JVM exists with code 130

fabien
  • 1,529
  • 1
  • 15
  • 28
  • Is the collection modified by several threads ? – Dici Oct 02 '15 at 16:29
  • There is an interval between the call to coll.size() and the iteration. There is no guarantee that the collection isn't modified in between. (This is at least a theoretical possibility, and since you can't provide a short example, one is permitted to have doubts.) – laune Oct 02 '15 at 16:31
  • The collection isn't modified by anything at this point unless a magic thread (which i didn't code) removes elements from it. There is actually no code that removes elements from that collection. – fabien Oct 02 '15 at 16:33
  • Do you control the code which populates/return this collection ? – Dici Oct 02 '15 at 16:34
  • Can you add one more Foo object to collection object and then iterate over it to check what exactly it prints whether 1 object or 2 ? You add it after System.out.println("collSize=" + coll.size()); Line... – Vasu Oct 02 '15 at 16:34
  • You should simply debug this... – wero Oct 02 '15 at 16:34
  • Sorry guys, my example was bad and not describing what is actually happening. I updated the post with the new info. – fabien Oct 02 '15 at 16:54
  • Does the VM in fact exit cleanly? Are any other messages displayed? What event causes the VM to shut down (normal exit, or termination by the system)? Do you see the same behavior if you omit the invocation of `o.bar()` in your loop? – John Bollinger Oct 02 '15 at 17:05
  • 1
    Could this simply be an I/O problem? Maybe the hook is performing all its work, but the progress messages are not making it to the console. – John Bollinger Oct 02 '15 at 17:10
  • The VM exists cleanly with code 130 (I hit Ctrl+C to kill it and want to release some resources when that happens). No crash logs, no exceptions. – fabien Oct 02 '15 at 19:56
  • It sounds like `o.bar()` blocked and didn't return. Any (local) resources will be cleaned up by the OS when the process exits so don't worry about those (open file handles, sockets, etc.) – dsh Oct 02 '15 at 20:26

2 Answers2

1

From the docs (emphasis mine) you're only promised "best effort" for shutdown hooks:

Shutdown hooks run at a delicate time in the life cycle of a virtual machine and should therefore be coded defensively. They should, in particular, be written to be thread-safe and to avoid deadlocks insofar as possible. They should also not rely blindly upon services that may have registered their own shutdown hooks and therefore may themselves in the process of shutting down. Attempts to use other thread-based services such as the AWT event-dispatch thread, for example, may lead to deadlocks.

Shutdown hooks should also finish their work quickly. When a program invokes exit the expectation is that the virtual machine will promptly shut down and exit. When the virtual machine is terminated due to user logoff or system shutdown the underlying operating system may only allow a fixed amount of time in which to shut down and exit. It is therefore inadvisable to attempt any user interaction or to perform a long-running computation in a shutdown hook.

So, basically if there's anywhere else to do it, do it there. If you must do it in a shutdown hook, be fast.

Community
  • 1
  • 1
Gus
  • 3,534
  • 1
  • 30
  • 39
  • I'm trying to release a bunch of resources when the user kills the VM with Ctrl+C. Time isn't a problem. I can have the hook waiting for 5 seconds and the hook is still fully executed. The stuff i'm trying to run is super fast anyway... – fabien Oct 02 '15 at 20:07
0

Turns out:

  • it was mainly a IO problem: unlike in the example above, i use a logger from log4j2 to print the info. log4j2 has its own shutdownHook which kills all the loggers faster than my shutdown hook since shutdown hooks are executed in parallel in the JVM. After disabling log4j2 shutdownHook, everything appeared to work as expected.
  • the hook was always executed fully (easily proven by attaching a debugger to the jvm)
  • in my particular case, i forgot to shutdown+await on my thread pools to do all the clean up i wanted to
  • i should have slept on it before posting here :/

Thank you all for the quick replies and help.

Community
  • 1
  • 1
fabien
  • 1,529
  • 1
  • 15
  • 28