I'm debugging a long request problem, which related to CompletableFuture.runAsync, which related to ForkJoinPool.commonPool.
The commonPool
's capacity is very small (for one machine it is set to 4). I think ForkJoinPool.commonPool blocks new Runnable if it is full. Am I correct?

- 912
- 6
- 16
1 Answers
What would happen if
ForkJoinPool.commonPool
is full?
The work queues for a ForkJoinPool
don't have any specific bounds, so it makes no sense to talk about a pool being "full".
And a ForkJoinPool
doesn't have a "capacity" either. It has a parallelism
parameter that defaults to a value based on the JVM's number of cores, but that doesn't limit the number of tasks that can be submitted.
If there are more tasks to run than there are worker threads to run them, then new tasks will be placed in a queue. The thread that submits the task is not "blocked" ... but the task itself will be delayed. (Just like an ExecutorService
with an unbounded work queue.)
However, you can run into problems if your FJP tasks do blocking I/O or use unmanaged (by the pool) synchronization. I have also heard of problems that can arise when an application ends up using more than one ForkJoinPool
. Look at this Q&A and see if it applies to your problem:

- 698,415
- 94
- 811
- 1,216
-
what if I submit a task beyond pool's capacity? – Gao Mar 19 '23 at 08:12
-
The task simply has to wait until one of the threads in the pool is available again. It will then *steal* the task and execute it. If you create a pool with 5 threads, it can execute 5 tasks concurrently. If you submit a 6th task, it has to wait until one of the 5 tasks is done. – Zabuzard Mar 19 '23 at 08:15
-
You are not supposed to submit very long or even forever-running tasks. Create separate pools for long living tasks or increase the capacity. Try to think more with a micro-task mindset, getting rid of super long tasks and splitting them into mini tasks. You can then use the future-chaining `future.thenApply(...).thenApply(...).thenAccept(...)`. With the virtual/green threads that arrive soon, this will be even more effective. – Zabuzard Mar 19 '23 at 08:19
-
2@Zabuzard I don’t see the point of splitting a linear task into smaller tasks that run one after the other anyway. That’s creating overhead for no benefit. – Holger Mar 20 '23 at 09:45
-
Kinda depends. But you give other tasks the chance to execute in-between. So you get more pseudo-parallism out of your pool. As in, dont create a single 24/7 task if you intend to execute sth else on the same single thread. Instead, make the tasks a bit smaller and something else can now get the chance to execute in between the cut points. – Zabuzard Mar 20 '23 at 11:06
-
2@Zabuzard there’s no guaranty that another task will be picked up in between these steps. In fact, when you use `thenApply`, `thenAccept`, etc without the `Async` suffix, the chances are especially low, as it doesn’t enqueue the dependent action. Even when using the `…Async` methods (without specifying a different pool), chances are low, as the Fork/Join framework has been designed specifically to give preference to local tasks, i.e. the one you just submitted in the best case. – Holger Mar 20 '23 at 17:34