Thread Pools That Cause OOM: Pitfalls of FixedThreadPool & CachedThreadPool

The article explains how Java's Executors utility creates thread pools that can unintentionally exhaust memory, detailing why FixedThreadPool with an unbounded queue and CachedThreadPool with unlimited threads often lead to OutOfMemoryError, and provides code examples and analysis from Alibaba's Java Development Handbook.

JavaEdge
JavaEdge
JavaEdge
Thread Pools That Cause OOM: Pitfalls of FixedThreadPool & CachedThreadPool

Pooling techniques are often used to cache objects whose creation incurs high performance costs; a pool pre‑creates such objects and reuses them after they are returned.

Manual Thread‑Pool Declaration

Developers can manually declare a thread pool, as illustrated in the accompanying diagram.

Convenient Creation via Executors

The JDK provides the Executors utility class with many shortcut methods for quickly creating thread pools.

FixedThreadPool Can Trigger OOM

When a single‑thread FixedThreadPool is initialized and each submitted task creates a large string and then sleeps, the JVM soon throws an OutOfMemoryError (GC overhead limit exceeded). The stack trace is shown below:

Exception in thread "http-nio-45678-ClientPoller"
java.lang.OutOfMemoryError: GC overhead limit exceeded

The underlying cause is that newFixedThreadPool builds its work queue as a LinkedBlockingQueue with the default capacity Integer.MAX_VALUE. This effectively creates an unbounded queue, which quickly fills up when tasks accumulate, exhausting heap memory.

Although newFixedThreadPool fixes the number of worker threads, the virtually unlimited task queue means that a large number of slow or memory‑intensive tasks can cause the JVM to run out of memory.

CachedThreadPool Can Also Lead to OOM

newCachedThreadPool

creates a thread pool whose maximum thread count is Integer.MAX_VALUE and whose work queue is a SynchronousQueue (a queue with no storage capacity). Each incoming request must be handled by an existing idle thread; if none is available, a new thread is created.

In a scenario where each task runs for about an hour, a burst of incoming tasks results in the creation of a huge number of threads. Since each thread consumes stack memory (e.g., 1 MB), the unbounded growth inevitably triggers an OutOfMemoryError such as "unable to create new native thread".

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

Reference

The observations are documented in the "Alibaba Java Development Manual".

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaThreadPoolOutOfMemoryErrorExecutors
JavaEdge
Written by

JavaEdge

First‑line development experience at multiple leading tech firms; now a software architect at a Shanghai state‑owned enterprise and founder of Programming Yanxuan. Nearly 300k followers online; expertise in distributed system design, AIGC application development, and quantitative finance investing.

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.