skip to content

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 pageshow

explore

questions

page 2 of 2

Given 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?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Look 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.

open as a page

Why is Executors.newFixedThreadPool considered risky in production, and how would you build a safer executor for a high-throughput service?

level: seniorimportance: should knowfreq 47%

basics

~20 s

newFixedThreadPool 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.

open as a page

How does the choice of work queue (bounded ArrayBlockingQueue, unbounded LinkedBlockingQueue, SynchronousQueue) change a ThreadPoolExecutor's behavior?

level: seniorimportance: should knowfreq 62%

basics

~20 s

An 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.

open as a page

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?

level: principalimportance: should knowfreq 38%

basics

~20 s

execute 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.

open as a page

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?

level: principalimportance: should knowfreq 34%

basics

~20 s

Size 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.

open as a page

How do you decide corePoolSize and maximumPoolSize for a real workload, and why is one-size-fits-all sizing dangerous?

level: principalimportance: should knowfreq 48%

basics

~20 s

It 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.

open as a page

What are the design limitations of java.util.concurrent.Future, and how do CompletableFuture and structured concurrency address them?

level: principalimportance: nice to knowfreq 40%

basics

~20 s

Plain 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.

open as a page

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?

level: principalimportance: nice to knowfreq 28%

basics

~20 s

Periodically 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.

open as a page

What subtle failure modes can CallerRunsPolicy introduce, and when is it the wrong backpressure choice?

level: principalimportance: nice to knowfreq 28%

basics

~20 s

CallerRunsPolicy 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.

open as a page

showing 31–39 of 39