Humm. Forgot about the AWT-Shutdown thread (that is controlling running and waiting for the shutdownhooks apparently).
Shit.
Edit. Okay here is a weaker version of that method that marks the Threads registed as shutdown hooks by the utility method that handles the TERM signal too.
The only thing missing i think is a to be sure that the NoClassDefFoundError is caught at the right place in vm’s that don’t have that class, or handle it another way if it is not.
/**
* This method kills this program and starts
* the given one.
*/
public static void restart(Class klass, String... args) {
try {
Runtime.getRuntime().addShutdownHook(new RestartProcessShutDownHook(klass, args));
Runtime.getRuntime().exit(0);
} catch (Exception ex) {
Logger.getLogger(IoUtils.class.getName()).log(Level.SEVERE, "Could not restart the program", ex);
}
}
private static final class RestartProcessShutDownHook extends Thread {
Class mainKlass;
String[] arguments;
public RestartProcessShutDownHook(Class mainKlass, String[] arguments) {
super();
this.mainKlass = mainKlass;
this.arguments = arguments;
}
@Override
public void run() {
try {
Thread[] tds = new Thread[Thread.activeCount()];
int var = Thread.enumerate(tds);
for (int i = 0; i < var; i++) {
Thread t = tds[i];
if (t != Thread.currentThread() &&
t.isAlive() &&
t.getName().equals("IoUtils.ShutdownHook")) {
t.join();
}
}
} catch (Exception ex) {
Logger.getLogger(IoUtils.class.getName()).log(Level.SEVERE, null, ex);
}
try {
forkJava(mainKlass, arguments);
} catch (Exception ex) {
Logger.getLogger(IoUtils.class.getName()).log(Level.SEVERE, "Couldn't fork java", ex);
}
}
}
/**
* Adds a shutdown hook that will be run when
* the program terminates.
* This is not the same as Runtime.getRuntime().addShutdownHook
* This hook will be run even if the program is terminated
* by a TERM signal. However that functionality depends on
* sun specific api.
* Otherwise it tries a best effort with shutdownhook
* (i've had shutdown hooks be terminated when running and
* corrupting data when O.S. shuts down).
* This method also give the guarantee that if using restart()
* and shutdownhooks added by the method,
* the application will be restarted only after the shutdown
* hooks run. (The TERM signal is not user sent so waiting for
* restart doesn't apply to it).
* @param r
*/
public static void addShutdownHook(final Runnable r) {
try {
sun.misc.SignalHandler handler = new sun.misc.SignalHandler() {
@Override
public void handle(sun.misc.Signal sig) {
r.run();
//if this is run the shutdown hooks can't be called.
Runtime.getRuntime().halt(0);
}
};
//only when the system is shutting down.
sun.misc.Signal.handle(new sun.misc.Signal("TERM"), handler);
} catch (NoClassDefFoundError ex) {
Logger.getLogger(IoUtils.class.getName()).log(Level.WARNING, "Not on a sun vm. Can't save state reliably.");
}
Thread t = new Thread(r, "IoUtils.ShutdownHook");
Runtime.getRuntime().addShutdownHook(t);
}