[concurrency-interest] ForkJoinPool sometimes blocks an outer on a nested task (Java 9 and later)

Lukas Rytz lukas.rytz at lightbend.com
Thu Oct 1 08:14:47 EDT 2020


Dear Experts

I'm new on this list and not a concurrency expert. I'm the lead of the
Scala team at Lightbend which maintains the compiler and standard library.

We recently had a bug report of a parallel collections operation being
blocked on the termination of a Future started within the operation body. I
managed to reproduce the behavior in a fairly small Java-only example using
ForkJoinPool, the code is here:
https://gist.github.com/lrytz/a622c541d91336030a8cb788273bdc66

The code starts a task, which forks two subtasks and joins them, the
subtasks recursively do the same, until some depth. Each one of these tasks
is fast (2ms). Additionally, the first task creates a subtask that is slow
(200ms), but does *not* join on it. On Java 8, each top-level task returns
quickly. On Java 9 and later, from time to time the top-level task gets
blocked on the slow subtask and only returns after 200+ ms. I tested Java
1.8.0_261-b12 for 8, and 9+181, 11.0.6+10, 14.0.1+7, 15+36-1562.

The issue is more common when the pool's parallelism is lower. With a
parallelism of 4, I did a 10 seconds flight recording, and there is a
pretty obvious difference: on Java 8 there were > 20 pool threads, while on
Java 11 there were only 5 of them. The screenshots show the long wait
periods on Java 11:
https://github.com/scala/bug/issues/12106#issuecomment-701978100.

I did a short search of this list's archive and found one thread that looks
somewhat related, though if I understand correctly that older discussion is
about tasks that involve some sort of blocking, which is not the case in
this example.
http://altair.cs.oswego.edu/pipermail/concurrency-interest/2014-May/012669.html

I'd like to know whether the Java 9+ behavior is a bug or within spec - I
hope it's an appropriate question for this list.
https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/ForkJoinPool.html
says:
>  The pool attempts to maintain enough active (or available) threads by
dynamically adding, suspending, or resuming internal worker threads, even
if some tasks are stalled waiting to join others

Best,
Lukas
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20201001/c62a825a/attachment.htm>


More information about the Concurrency-interest mailing list