stonar96
stonar96

Reputation: 1469

Can the JVM poll for asynchronous exceptions just before entering a try-block?

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

Answers (0)

Related Questions