What is the RejectedExecutionHandler in ThreadPoolExecutor? How can you customize it?

RejectedExecutionHandler is the callback interface a ThreadPoolExecutor invokes when it cannot accept a new task — typically because both its worker threads and its task queue are already full — letting you define custom behavior instead of the default hard failure.

Key Points: • The four built-in policies are AbortPolicy (throws RejectedExecutionException, the default), CallerRunsPolicy (runs the task on the submitting thread), DiscardPolicy (silently drops it), and DiscardOldestPolicy (drops the oldest queued task and retries). • You implement it by overriding rejectedExecution(Runnable r, ThreadPoolExecutor executor) with custom logic such as logging, alerting, retry queues, or routing to a fallback executor. • CallerRunsPolicy is a common backpressure technique — it slows down the producer thread by making it do the work itself, which naturally throttles submission rate. • Custom handlers are set either through the ThreadPoolExecutor constructor or via setRejectedExecutionHandler(). • Choosing the right policy depends on whether losing a task is acceptable, or whether backpressure/retry is more appropriate for the workload.

Example: A high-throughput ingestion service might implement a custom handler that pushes rejected tasks onto a dead-letter queue for later reprocessing instead of silently dropping them or throwing an unhandled exception that could crash the caller.

Code Example:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    4, 8, 60, TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(100),
    (r, exec) -> {
        // custom handling, e.g. log and route to a fallback
        log.warn("Task rejected, running on caller thread");
        r.run();
    });

Interview Tip: A concise interview answer is:

"RejectedExecutionHandler defines what happens when a ThreadPoolExecutor can't accept a task because its queue and pool are both full. The built-in options are abort, caller-runs, discard, and discard-oldest, and you can implement your own to log, retry, or route overflow tasks instead of just failing outright."