Class BoundedExecutorService

java.lang.Object
java.util.concurrent.AbstractExecutorService
org.apache.camel.util.concurrent.BoundedExecutorService
All Implemented Interfaces:
Executor, ExecutorService

An ExecutorService wrapper that enforces bounded concurrency via a Semaphore.

When virtual threads are enabled, Camel replaces the traditional ThreadPoolExecutor with Executors.newThreadPerTaskExecutor(), which accepts every task immediately (unbounded). This wrapper limits the maximum number of tasks delegated to the underlying executor. Unlike ThreadPoolExecutor there is no distinction between pool threads and queued tasks — the semaphore enforces a flat concurrency cap on delegated tasks.

When the semaphore has no available permits, behavior depends on the configured ThreadPoolRejectedPolicy:

  • CallerRuns (default): blocks until a permit is available or the timeout expires; on timeout, runs the task on the caller's thread. Tasks are never lost. Note that caller-run tasks execute outside semaphore accounting, so total system concurrency may temporarily exceed maxConcurrent.
  • Abort: blocks until a permit is available or the timeout expires; on timeout, throws RejectedExecutionException.
  • Block: blocks indefinitely until a permit becomes available. No timeout, no rejection.

Caller thread blocking: while waiting for a permit, the calling thread is blocked. When callers are virtual threads this is inexpensive (the carrier thread is released). When callers are platform threads (e.g., HTTP server threads) the blocked thread is unavailable for other work — this is standard backpressure behavior but worth noting for capacity planning.