Executor Framework
The Executor framework: submitting tasks to managed thread pools instead of creating threads by hand, plus queueing, rejection, lifecycle and sizing. This is the most practically relevant concurrency area in backend interviews because pool misconfiguration is a real production failure mode.
part ofJavaoverview, primer and where to startread it →on this pageshowhide
explore
- Executor & ExecutorService5 questions
- ThreadPoolExecutor Tuning5 questions
- Work Queues & Rejection Policies5 questions
- Executors Factory Methods & Risks5 questions
- ExecutorService Lifecycle & Sizing4 questions
- ScheduledExecutorService5 questions
- Callable, Future & CompletionService5 questions
- Thread Pool Monitoring5 questions
questions
page 2 of 2Given a ThreadPoolExecutor whose latency is rising, how do you combine its monitoring signals (activeCount, poolSize, queue size, completedTaskCount) to diagnose whether the pool is saturated, mis-sized, or stalled?
basics
~20 sLook at the numbers together: if active threads equal max and the queue keeps growing, the pool is saturated. If completed tasks stop increasing while threads stay busy, tasks are stalled (blocked). If the queue stays empty and threads are mostly idle, the pool isn't the problem.
Why is Executors.newFixedThreadPool considered risky in production, and how would you build a safer executor for a high-throughput service?
basics
~20 snewFixedThreadPool uses an unbounded LinkedBlockingQueue, so under overload the queue grows without limit and can run the JVM out of memory instead of rejecting work. A safer setup constructs a ThreadPoolExecutor directly with a bounded queue and an explicit rejection policy.
How does the choice of work queue (bounded ArrayBlockingQueue, unbounded LinkedBlockingQueue, SynchronousQueue) change a ThreadPoolExecutor's behavior?
basics
~20 sAn unbounded queue stores unlimited waiting tasks, so the pool never grows past its core size and can run out of memory. A bounded queue limits waiting tasks and lets the pool add threads up to the max. A SynchronousQueue holds nothing, handing each task directly to a thread.
As a system grows, why is choosing and owning the Executor's execution policy (pool sizing, queue, rejection) more important than which submission method you call? How does the Executor abstraction help, and where does it fall short?
basics
~20 sexecute vs submit is a small local choice. What really controls behavior under load is the execution policy: how many threads, how big the queue, and what happens when both are full. The Executor interface hides that policy behind one method, so you can set it centrally — but it can't pick the right numbers for you or stop teams from sharing one pool unsafely.
How would you size and operate a ScheduledExecutorService for many recurring jobs, and what are the limits of its timing guarantees compared to a dedicated scheduler?
basics
~20 sSize the pool so concurrently-due tasks aren't starved: a single thread serializes everything, so one slow job delays the rest. ScheduledExecutorService gives relative, best-effort timing with no persistence, no cron expressions, and no clustering — for those you reach for Quartz, a cron service, or a distributed scheduler.
How do you decide corePoolSize and maximumPoolSize for a real workload, and why is one-size-fits-all sizing dangerous?
basics
~20 sIt depends on whether tasks mostly use the CPU or mostly wait (on I/O). CPU-bound work needs roughly as many threads as CPU cores; I/O-bound work can use many more because threads spend most of their time waiting. Always measure rather than guess.
What are the design limitations of java.util.concurrent.Future, and how do CompletableFuture and structured concurrency address them?
basics
~20 sPlain Future only lets you block on get() or poll isDone() — you can't attach a callback, chain steps, or combine several Futures without blocking a thread. CompletableFuture adds non-blocking composition and callbacks; structured concurrency manages a whole group of tasks with shared cancellation and scope.
How would you continuously expose a ThreadPoolExecutor's monitoring signals to an external observability system (JMX, Micrometer/Prometheus), and what are the pitfalls of doing it safely at scale?
basics
~20 sPeriodically read the pool's accessors (active, pool size, queue size, completed tasks) and publish them as metrics, e.g. register gauges with Micrometer or expose an MBean over JMX, so a system like Prometheus can scrape and graph them.
What subtle failure modes can CallerRunsPolicy introduce, and when is it the wrong backpressure choice?
basics
~20 sCallerRunsPolicy runs the rejected task on the submitting thread. If that thread is a critical or shared thread (like an event loop or another pool's worker), running long tasks there can stall the system or even deadlock. It also makes task latency unpredictable for the unlucky caller.
showing 31–39 of 39