Reputation: 1469
Recently I read about JLS 11.1.3. Asynchronous Exceptions. I was wondering if there are any specifications about where polling for asynchronous exceptions (and throwing them) can or cannot happen. Consider for example the following code:
try {
statement1();
} finally {
// comment
try {
statement2();
} finally {
statement3();
}
}
If an asynchronous exception is polled and thrown at any statement#()
, the other statements will still be attempted to be executed. However, can there be a valid implementation of the JVM, that polls asynchronous exceptions just before entering the try
-block at the // comment
, so that neither of the two remaining statements are attempted to be executed?
The JLS says that asynchronous Exceptions "can potentially occur at any point in the execution of a program", but is there a statement necessary for a poll, and if so, what exactly counts as a statement?
I have also written some test code that triggers asynchonous exceptions by calling the deprecated Thread#stop()
method.
private static volatile boolean hot = false;
private static volatile boolean state1 = false;
private static volatile boolean state2 = false;
private static volatile boolean state3 = false;
private static volatile boolean dummyOperationState = false;
public static void main(String[] args) {
for (int i = 1;; i++) {
hot = false;
state1 = false;
state2 = false;
state3 = false;
Thread thread = new Thread(() -> {
try {
while (true) {
try {
state1 = true;
dummyOperationState = !dummyOperationState;
} finally {
// dummyOperationState = !dummyOperationState;
try {
state2 = true;
dummyOperationState = !dummyOperationState;
} finally {
state3 = true;
dummyOperationState = !dummyOperationState;
}
}
// Replace the above code by this:
/* state1 = true;
dummyOperationState = !dummyOperationState;
state2 = true;
dummyOperationState = !dummyOperationState;
state3 = true;
dummyOperationState = !dummyOperationState; */
state1 = false;
state2 = false;
state3 = false;
hot = true;
}
} finally {
hot = false;
}
});
thread.setDaemon(true);
thread.start();
while (!hot);
// Add some randomness.
int random = (int) (Math.random() * 100.);
for (int j = 0; j < random; j++) {
Math.sin(Math.sqrt(j * 2.));
}
thread.stop();
while (hot);
if (state1 && !state2 && !state3) {
System.out.println("run: " + i);
System.out.println("state1: " + state1);
System.out.println("state2: " + state2);
System.out.println("state3: " + state3);
break;
}
if (i % 1000 == 0) {
System.out.println(i);
}
}
}
The dummyOperationState = !dummyOperationState;
statements aren't really required, but it seems like the compiler makes too many optimizations without them to demonstrate the commented out code. The program as shown above doesn't terminate when I run it. My question is, is this guaranteed by any valid JVM implementation (provided that no other or further exceptions occur than the triggered ThreadDeath
)?
When I turn the first comment // dummyOperationState = !dummyOperationState;
into a statement, an asynchronous exception can be polled there and the program may terminate, which is exactly what happens in my tests after a few runs. The commented out code just demonstrates the case without the try
-finally
-blocks, which will also terminate at some point.
Upvotes: 1
Views: 107