Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ExecutorService workStealingPool and cancel method

Can you think about any reason why this code doesn't work and always outputs "finished", but the second example works without any problems. I'm using latest JDK (8u45).

public static class MyClass implements Runnable {

        @Override
        public void run() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException ex) {
                System.out.println("Interrupted");
                return;
            }
            System.out.println("Finished");
        }

        public static void main(String[] args) {
             // spot the difference ->
             ExecutorService executorService = Executors.newWorkStealingPool(4);
             Future future = executorService.submit(new MyClass());
             Thread.sleep(100);
             future.cancel(true);
        }
    }

And the following example works flawlessly:

public static class MyClass implements Runnable {

        @Override
        public void run() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException ex) {
                System.out.println("Interrupted");
                return;
            }
            System.out.println("Finished");
        }

        public static void main(String[] args) {
             ExecutorService executorService = Executors.newSingleThreadExecutor();
             Future future = executorService.submit(new MyClass());
             Thread.sleep(100);
             future.cancel(true);
        }
    }

EDIT: Added return and updated sleep times and another example.

like image 701
JiriS Avatar asked Apr 27 '15 18:04

JiriS


2 Answers

It's simpler than I thought originally. The problem is that work-stealing-pool is internally using ForkJoinPool and ForkJoinTask doesn't support cancel(true) and therefore it's not possible to cancel task after the task is started.

See javadoc documentation (http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinTask.html):

   mayInterruptIfRunning - this value has no effect in the default implementation 
   because interrupts are not used to control cancellation.
like image 159
JiriS Avatar answered Sep 18 '22 05:09

JiriS


There is no way to forcibly terminate a Thread in Java. (Twenty years ago, Java 1.0 tried to provide this, and it turned out to be unworkable; the methods which attempted to do it are deprecated with no replacement.)

You, as the author of the Runnable, are responsible for properly responding to an interrupt by cleanly terminating your own run method. In your case, you should have exited your run method in the catch-block, but you didn't; you let the method's logic continue past the catch-block. So even when the thread is interrupted, the run method's last statement is always executed.

like image 24
VGR Avatar answered Sep 19 '22 05:09

VGR