[concurrency-interest] ForkJoin refresh

Doug Lea dl at cs.oswego.edu
Tue Feb 4 14:52:06 EST 2020

I mentioned a few weeks ago that most uses of
Executors.newFixedThreadPool(n) (based on TPE ThreadPoolExecutor) should
instead use "new ForkJoinPool(n)", This led to more systematic removal
of FJP-TPE differences in new FJ update. Among the issues are default
interrupt policies for ForkJoinTasks that wrap Callables and Runnables.
The ExecutorService invokeAny and invokeAll methods for arrays of
Callables are specified in a way that makes users expect that cancelled
tasks are interrupted. So they now are. Further, in addition to
internally forcing this for only these methods, there is now a way that
anyone can obtain this effect for any wrapped Callable (exposing a hack
that I've suggested in response to desperate queries). New method
adaptInterruptible(Callable) has class-level description as follows:

 * <p>By default, method {@link #cancel} ignores its {@code
 * mayInterruptIfRunning} argument, separating task cancellation from
 * the interruption status of threads running tasks. However, the
 * method is overridable to accommodate cases in which running tasks
 * must be cancelled using interrupts. This may arise when adapting
 * Callables that cannot check {@code isCancelled()} task status.
 * Tasks constructed with the (@link #adaptInterruptible) adaptor
 * track and interrupt the running thread upon {@code
 * cancel(true)}. Reliable usage requires awareness of potential
 * consequences: Method bodies should ignore stray interrupts to cope
 * with the inherent possibility that a late interrupt issued by
 * another thread after a given task has completed may (inadvertently)
 * interrupt some future task. Further, interruptible tasks should not
 * in general create subtasks, because an interrupt intended for a
 * given task may be consumed by one of its subtasks, or vice versa.

(Formatted in context at:

The intent of this description is to also help explain why most
ForkJoinTasks should not and do not interrupt when cancelling. Doing
otherwise would lead to constant surprises about both "missed" and
"spurious" interrupts, without any sure way to fix these problems. But
adaptInterruptible can still be useful when restricted to those
occasional cases (often legacy code) where such things can be tolerated.

Beyond these, the only difference between fixed-pool TPE and FJP that
could conceivably matter is that FJP.shutdownNow does not return a
collection of tasks that did not run because of pool termination.
(Because there is no central queue, it does not know which tasks are
cancelled due to termination vs otherwise.)

Comments and suggestions are welcome.

On 1/17/20 4:39 PM, Doug Lea via Concurrency-interest wrote:
> It would be great to get feedback from other usages before integrating
> into OpenJDK. As usual, you can try it with any JDK11+ JVM by grabbing
> http://gee.cs.oswego.edu/dl/concurrent/dist/jsr166.jar and running "java
> --patch-module java.base="$DIR/jsr166.jar", where DIR is the full file
> prefix. (Although beware that using --patch-module slows down startup,
> and occasionally entire test runs. For other options, see
> http://gee.cs.oswego.edu/dl/concurrency-interest/index.html).

More information about the Concurrency-interest mailing list