This code will deadlock:
public class Main {
static public final Object a = new Object();
static {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() { if (a == null); }
});
System.exit(0);
}
static public void main(final String[] args) {}
}
This code will exit normally:
public class Main {
static public final Object a = new Object();
static {
final Object aa = a;
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() { if (aa == null); }
});
System.exit(0);
}
static public void main(final String[] args) {}
}
What is happening?
It's common for a script to rely on the exit codes of commands it invokes. If such a command is a Java application, then System. exit is handy for sending this exit code. For example, instead of throwing an exception, we can return an abnormal exit code that can then be interpreted by the calling script.
getRuntime(). addShutdownHook(new Thread() { public void run() { System. out. println("Running Shutdown Hook"); } }); will print a Running Shutdown Hook at the time of program termination at any point.
It is important that classes are not accessed concurrently whilst initialising, so a lock is held.
I guess what is happening in the first case is:
Main
.System.exit
blocks as it does not return.Main
class to read a field, but blocks as the class is initialising.Hence the deadlock. It's a little clearer if you write if (a == null);
as if (Main.a == null);
.
In the second case, the value is copied and therefore the shutdown hook does not need to access the Main
class.
Moral: Don't mix threads and class initialisation. Gafter and Bloch's Java Puzzlers book has more on this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With