A fixed pool with a bounded queue, for work that must not be allowed to pile up without limit.
The alternative — Future on ExecutionContext.global — is a poor fit for shelling out to a subprocess. Its queue is unbounded, so a burst is accepted in full and the clients at the back have long since timed out by the time their work runs.
Here, saturation is visible instead. submit returns None rather than queueing without limit, which lets the caller shed load — an immediate "busy" is a better answer than a response nobody is waiting for any more.
This is a real java.util.concurrent.Executor, so it can be handed to anything that takes one — ExecutionContext.fromExecutor, CompletableFuture.supplyAsync, and so on.
maxWait allows the bounded queue to limit how much work is accepted; tasks are discarded if they wait too long for a worker rather than being run.
Value parameters
maxWait
How long a task may sit in the queue before a worker discards it rather than running it. Applies to submit only — see execute for why. Zero or negative means no deadline: queued work always runs, however long it waited.
name
Prefix for the worker thread names, so stack dumps say which pool is busy
How many tasks have been discarded for waiting past maxWait instead of being run.
How many tasks have been discarded for waiting past maxWait instead of being run.
Worth watching: a number that climbs says the queue is deeper than the service can drain within the deadline, so either threads is too low for the arrival rate or queueSize is promising more than it can keep.
Run command on this pool, per the java.util.concurrent.Executor contract: no handle on the result, and saturation reported by throwing rather than by a return value.
Run command on this pool, per the java.util.concurrent.Executor contract: no handle on the result, and saturation reported by throwing rather than by a return value.
A command that throws is left to the pool's usual handling. Callers that want the failure back, or that would rather shed load than catch, should use submit instead.
Note that maxWait is deliberately not applied here. Once accepted, a command always runs. Silently dropping it would break every wrapper built on this interface.
There are two ways this sheds load, and they are reported differently because they are known at different times. A full queue is known immediately, so it comes back as None. Having waited past maxWait is only known once a worker picks the task up, by which point the caller already holds a Future — so that arrives as a BoundedExecutor.StaleWorkException on the Future. Both mean the same thing to a caller: the work did not run and will not, because the service is over capacity.
Attributes
Returns
The eventual result, or None if the pool and its queue are both full. A body that throws fails the returned Future; it does not take the worker thread down with it.