JDK-8213115 : ThreadPerTaskExecutor of CompletableFuture makes it unreliable
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.util.concurrent
  • Affected Version: 8,11,12
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • Submitted: 2018-10-27
  • Updated: 2025-06-18
  • Resolved: 2025-06-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 25
25Resolved
Related Reports
Duplicate :  
Description
A DESCRIPTION OF THE PROBLEM :
The documentation of CompletableFuture (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) states:
> All async methods without an explicit Executor argument are performed using the ForkJoinPool.commonPool() (unless it does not support a parallelism level of at least two, in which case, a new Thread is created to run each task)

This means these methods cannot be used reliably when you don't know for sure that the environment, where your application runs, creates the common pool with a default parallelism of at least two.
Otherwise execessive use of these methods can cause an `OutOfMemoryError`.

A good example for this is https://bugs.mojang.com/browse/MC-137353.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Maybe `CompletableFuture` should use a replacement pool with at least two workers, or commonPool() should always have at least two workers (might break existing programs)?


Comments
This was addressed as a byproduct of https://bugs.openjdk.org/browse/JDK-8350493
12-06-2025

When CompletableFuture was first introduced, this seemed to be the only acceptable (but not very nice) policy available. The need for an internal default can always be avoided by using the explicit Executor versions of methods. With the deprecation of SecurityManagers and introduction of VirtualThreads, this could be changed either use a common ForkJoinPool(2) or VirtualThread per action. This would be a possibly-incompatible change though.
18-08-2022

I think this may have gone unnoticed by the assignee. Neither [~dl] or [~martin] seem aware of it.
18-08-2022