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.
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.
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.
上一篇: 为什么在java中使用线程有两种方式?