Skip to content

chore: use JDK11 constructor for ForkJoinPool (support setting maximum spare threads) #32745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jul 1, 2025

Conversation

leviramsey
Copy link
Contributor

@leviramsey leviramsey commented Jun 20, 2025

Scala code (via BlockContext so Await/blocking) and Java code (via ManagedBlocker) can signal a ForkJoinPool that it might be useful to add a worker thread to compensate for the present worker being blocked. For the common pool, the number of additional workers can be bounded by a JVM property (default value is 256); it is unclear whether this property also applies this property does not apply to application constructed FJPs like the default dispatcher (or whether the effective maximum spare threads for a dispatcher is 2^15 - parallelism). JDK11 adds a constructor which allows setting this maximum (among a few other settings).

Regardless of whether the default behavior of the currently-used constructor takes a limit from the property, it seems useful to expose this setting in config. The default chosen is 256 to match the property's default (which is doubtless better than the previous de facto "no limit" if the current behavior is not to consult the property!). In addition to overriding via config, the value of the JDK property for the common pool may also be used (as the default dispatcher is the Akka analogue to the common pool).

The priority for setting values for this setting for the default dispatcher (inherited by user-defined dispatchers) is:

  • explicit JVM property akka.actor.default-dispatcher.fork-join-executor.maximum-spare-threads
  • akka.actor.default-dispatcher.fork-join-executor.maximum-spare-threads in config (can be overridden by the usual config methods)
  • JVM property java.util.concurrent.ForkJoinPool.common.maximumSpares

The internal dispatcher is hardcoded to have zero spares: there shouldn't be anything that blocks in that dispatcher.

Copy link
Contributor

@johanandren johanandren left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, one nitpick.

Copy link
Contributor

@patriknw patriknw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generally mean more context switches by the OS kernel and decreased application throughput with unpredictable latencies.
Assuming the system remains under load, these spare threads will be kept busy and not become idle; even a relatively
infrequent use of this mechanism under load may eventually exhaust the ability to add threads, resulting in a crash
"out of the blue".
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really torn on whether to include an "if going down this path, be sure to set maximum-spare-threads" advisory here... I suppose it would be in the spirit of "if skydiving, be sure to have a parachute".

@johanandren johanandren merged commit cb88b7f into akka:main Jul 1, 2025
5 checks passed
@johanandren johanandren added this to the 2.10.7 milestone Jul 1, 2025
@leviramsey leviramsey deleted the dispatcher-max-spares branch July 1, 2025 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants