6

We want to execute some java code or shell code before a JVM exits when it is killed manually. Our application is not running in a container. We need to monitor it automatically using the Java code itself or some command line tool.

Charity Leschinski
  • 2,886
  • 2
  • 23
  • 40
Chris
  • 6,431
  • 10
  • 44
  • 59

3 Answers3

14

You can add a shutdown hook by using Runtime.getRuntime().addShutdownHook(). Such a shutdown hook is run by the JVM, once the JVM' process terminates. However, note that this is not always the case. A JVM might get killed before it gets the chance to trigger its shutdown hooks. This is mentioned in the javadoc:

In rare circumstances the virtual machine may abort, that is, stop running without shutting down cleanly. This occurs when the virtual machine is terminated externally, for example with the SIGKILL signal on Unix or the TerminateProcess call on Microsoft Windows. The virtual machine may also abort if a native method goes awry by, for example, corrupting internal data structures or attempting to access nonexistent memory. If the virtual machine aborts then no guarantee can be made about whether or not any shutdown hooks will be run.

You can use a shut down hook as follows:

Runtime.getRuntime().addShutdownHook(
  new Thread("app-shutdown-hook") {
    @Override 
    public void run() { 
      System.out.println("bye"); 
    }
});

You can and should also deregister a shut down hook once it is no longer required. Otherwise, the JVM can never garbage collect the hook.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
bobah
  • 18,364
  • 2
  • 37
  • 70
  • 1
    You have been around for long enough to know that this is not a proper answer. Please add at least a small description for why this works. – Rafael Winterhalter May 06 '14 at 06:41
  • I tried this on my Linux server. It does not work. If the JVM process be killed by Ctrl+C, it works. But if the JVM process be killed by other process via kill -9 {PID}, then it does not work. Our application more like kill -9 {PID} way. – Chris May 06 '14 at 06:55
  • @Chris: an innocent question: who is killing your java app with the KILL signal ? Do you do that on purpose, or you just want to be sure you have a chance to take action no matter what ? – Costi Ciudatu May 06 '14 at 06:57
  • As mentioned in @fge's answer, a `SIGKIL` will kill the entire process and do not leave the process a chance to trigger its shutdown hooks. `CTRL + C` triggers such a `SIGKIL` command. There is nothing you can do (besides running a second process which cleans up after your process manually.) – Rafael Winterhalter May 06 '14 at 07:05
  • @Costi if a jvm process run for a long time, we will kill it. But we need to log how many and when a jvm process be killed – Chris May 06 '14 at 07:12
  • @Chris - there are enough command line tools on Linux to collect the process runtime profile before killing it. With Java, though, some people use the combo "kill -3; sleep X; kill -TERM; sleep X;" kill -KILL" to dump stack trace, let program exit gracefully and only if it has not kill it forcefully. As many said interceptig kill signal is undefined behavior on Unix so it is the last thing you'd want to do. – bobah May 06 '14 at 07:36
  • @bobah I think your right, we should use Linux tools instead of relaying JVM itself. How can I make a comment to the solution? – Chris May 06 '14 at 07:42
  • 2
    @raphw: Ctrl-C triggers a SIGINT by default, *not* a SIGKILL. – Costi Ciudatu May 06 '14 at 08:29
  • @Costi Ciudatu you are right of course, I am currently working under Windows where `CTRL + C` indeed kills a process. I got the two mixed up. Thanks for correcting this. – Rafael Winterhalter May 06 '14 at 08:40
2

Not sure what you mean by "killed"?

If it is by a signal, it depends on the signal. For some of these you can add a JVM shutdown hook which the JVM will execute... But not all. SIGKILL is instant death for instance.

With shell code you can do that:

my java command;
# inspect $?

Run that as a background process; you can tell whether the JVM was killed by inspection of $? since it will be 128 or greater (127 + number of signal used to kill).

Note that you can BOTH capture the command output if needed AND inspect $?:

output=$(my java command);
# inspect $? -- ONLY THEN inspect $output

Of course, add quotes where appropriate etc etc.


And of course you can also store the value of $? before inspecting it later:

my command;
RC=$?;
# do something else
# inspect $RC

Finally, it is important to note that in custom code which uses System.exit() you should avoid exiting with 1: the JVM will exit with that return code whenever main() throws anything.

fge
  • 119,121
  • 33
  • 254
  • 329
  • Is there a shell that would allow you to set `$?` to a string ? I think what you meant was: `java -jar...; ret=$?; # inspect $ret`. – Costi Ciudatu May 06 '14 at 06:40
  • It's the return code... But you don't set it yourself; the shell will store the return code into `$?` and you can assign that to your own variable, as it's quite volatile. – Costi Ciudatu May 06 '14 at 06:43
  • Also, it is not that volatile; it will always refer to the last command/builtin executed – fge May 06 '14 at 06:44
  • Yes, but "the last" command changes with every `ls` or `cd` :). And you may want to do other things before actually inspecting that return code. – Costi Ciudatu May 06 '14 at 06:44
  • Eh? Not within a script! It refers to the last command executed before you inspect it -- ALWAYS – fge May 06 '14 at 06:45
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/52078/discussion-between-costi-ciudatu-and-fge) – Costi Ciudatu May 06 '14 at 06:45
0

Please see this post. You just have to tell the runtime you want to execute it at the end of everything. Tada.

Community
  • 1
  • 1
Christopher Wirt
  • 1,108
  • 1
  • 10
  • 21