future.cancel does not work

teglus picture teglus · Jan 20, 2015 · Viewed 7.7k times · Source

I have a nice and compact code, which does not work as I expected.

public class Test {

    public static void main(String[] args) {

        Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                    for (;;) {

                    }
                } finally {
                    System.out.println("FINALLY");
                }

            }
        };

        ExecutorService executor = Executors.newSingleThreadExecutor();

        Future<?> future = executor.submit(r);
        try {
            future.get(3, TimeUnit.SECONDS);
        } catch (TimeoutException e) {
            boolean c = future.cancel(true);
            System.out.println("Timeout " + c);
        } catch (InterruptedException | ExecutionException e) {
            System.out.println("interrupted");
        }
        System.out.println("END");

    }

}

The output is :

Timeout true

END

Question: Why does not terminate the future.cancel(true) method the called Runnable? After the program wrote the "END" to the output, the "r" Runnable is still running.

Answer

assylias picture assylias · Jan 20, 2015

The problem is that your Runnable is not interruptible: task interruption is a collaborative process in Java and the cancelled code needs to check regularly if it's been cancelled otherwise it won't respond to the interruption.

You can amend you code as follows and it should work as expected:

Runnable r = new Runnable() {
    @Override public void run() {
        try {
            while (!Thread.currentThread.isInterrupted()) {}
        } finally {
            System.out.println("FINALLY");
        }
    }
};