ForkJoinPool resets thread interrupted state ForkJoinPool resets thread interrupted state multithreading multithreading

ForkJoinPool resets thread interrupted state


This happens because Future<?> is a ForkJoinTask.AdaptedCallable which extends ForkJoinTask, whose cancel method is:

public boolean cancel(boolean mayInterruptIfRunning) {    return setCompletion(CANCELLED) == CANCELLED;}private int setCompletion(int completion) {    for (int s;;) {        if ((s = status) < 0)            return s;        if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) {            if (s != 0)                synchronized (this) { notifyAll(); }            return completion;        }    }}

It does not do any interruptions, it just sets status. I suppose this happens becouse ForkJoinPools's Futures might have a very complicated tree structure, and it is unclear in which order to cancel them.


Sharing some more light on top of @Mkhail answer:

Using ForkJoinPool execute() instead of submit() will force a failed Runnable to throw a worker exception, and this exception will be caught by the Thread UncaughtExceptionHandler.

Taking from Java 8 code:
submit is using AdaptedRunnableAction().
execute is using RunnableExecuteAction() (see the rethrow(ex)).

 /** * Adaptor for Runnables without results */static final class AdaptedRunnableAction extends ForkJoinTask<Void>    implements RunnableFuture<Void> {    final Runnable runnable;    AdaptedRunnableAction(Runnable runnable) {        if (runnable == null) throw new NullPointerException();        this.runnable = runnable;    }    public final Void getRawResult() { return null; }    public final void setRawResult(Void v) { }    public final boolean exec() { runnable.run(); return true; }    public final void run() { invoke(); }    private static final long serialVersionUID = 5232453952276885070L;}/** * Adaptor for Runnables in which failure forces worker exception */static final class RunnableExecuteAction extends ForkJoinTask<Void> {    final Runnable runnable;    RunnableExecuteAction(Runnable runnable) {        if (runnable == null) throw new NullPointerException();        this.runnable = runnable;    }    public final Void getRawResult() { return null; }    public final void setRawResult(Void v) { }    public final boolean exec() { runnable.run(); return true; }    void internalPropagateException(Throwable ex) {        rethrow(ex); // rethrow outside exec() catches.    }    private static final long serialVersionUID = 5232453952276885070L;}