Mastering Java ThreadPool Rejection Policies: When and How to Use Them

This article explains the four standard Java ThreadPoolExecutor rejection policies—AbortPolicy, CallerRunsPolicy, DiscardOldestPolicy, and DiscardPolicy—detailing their behavior, suitable scenarios, and providing full code examples, plus guidance on creating custom policies.

Xuanwu Backend Tech Stack
Xuanwu Backend Tech Stack
Xuanwu Backend Tech Stack
Mastering Java ThreadPool Rejection Policies: When and How to Use Them

Thread pools provide four standard rejection policies.

AbortPolicy (throws exception, handled by caller) : the default policy that throws a RejectedExecutionException, discarding the task; suitable when immediate awareness of rejection is needed.

public static class AbortPolicy implements RejectedExecutionHandler {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());
    }
}

CallerRunsPolicy (caller runs the task) : does not discard or throw; the calling thread executes the task, slowing submission speed; suitable when tasks must not be lost.

public static class CallerRunsPolicy implements RejectedExecutionHandler {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            r.run();
        }
    }
}

DiscardOldestPolicy (discard oldest task) : discards the oldest task in the queue and resubmits the new one; useful when only the latest tasks matter, such as real‑time data processing.

public static class DiscardOldestPolicy implements RejectedExecutionHandler {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            e.getQueue().poll(); // discard oldest
            e.execute(r); // submit new task
        }
    }
}

DiscardPolicy (silently discard) : simply discards the task without throwing an exception; appropriate when loss is acceptable, e.g., logging.

public static class DiscardPolicy implements RejectedExecutionHandler {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        // do nothing, discard task
    }
}

In addition, you can implement a custom rejection policy by implementing the RejectedExecutionHandler interface.

public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        // custom handling logic
    }
}
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    2, 4, 60L, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(2),
    new CustomRejectedExecutionHandler()
);
JavaconcurrencyThreadPoolRejectionPolicy
Xuanwu Backend Tech Stack
Written by

Xuanwu Backend Tech Stack

Primarily covers fundamental Java concepts, mainstream frameworks, deep dives into underlying principles, and JVM internals.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.