Backend Development 19 min read

How Many Requests Can a Default SpringBoot App Handle? Inside Tomcat & Undertow Thread Pools

This article walks through an interview question about the maximum concurrent requests a default SpringBoot application can process, builds a minimal demo, examines Tomcat and Undertow thread‑pool configurations, and shows how container defaults and parameters like core size, max size, and queue length determine the real limit.

macrozheng
macrozheng
macrozheng
How Many Requests Can a Default SpringBoot App Handle? Inside Tomcat & Undertow Thread Pools

Interview Question

A reader asked:

A SpringBoot project with no special configuration, using all default settings, how many requests can it handle simultaneously?

The key is to clarify the web container and its thread‑pool defaults before answering.

Demo Setup

We create a minimal SpringBoot 2.7.13 project with only two dependencies and an empty

application.properties

. The only controller is:

<code>@Slf4j
@RestController
public class TestController {
    @GetMapping("/getTest")
    public void getTest(int num) throws Exception {
        log.info("{} received request:num={}", Thread.currentThread().getName(), num);
        TimeUnit.HOURS.sleep(1);
    }
}
</code>

A load‑test class spawns many threads that call the endpoint:

<code>public class MainTest {
    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            int finalI = i;
            new Thread(() -> {
                HttpUtil.get("127.0.0.1:8080/getTest?num=" + finalI);
            }).start();
        }
        Thread.yield();
    }
}
</code>

Running the demo and the test shows the log line from

TestController

appear for each request.

Answer for Tomcat (default container)

Tomcat’s thread pool defaults are:

corePoolSize = 10

maximumPoolSize = 200

queue length = Integer.MAX_VALUE (effectively unlimited)

Tomcat’s execution order is core → max → queue, so once the 10 core threads are busy it immediately creates up to 200 threads. Therefore, a default SpringBoot application can handle up to 200 concurrent requests.

We can verify these numbers via a thread dump showing

org.apache.tomcat.util.threads.ThreadPoolExecutor

and its

corePoolSize

and

maximumPoolSize

values.

Why the number can change

Other Tomcat parameters affect the limit:

server.tomcat.max-connections

(default 8192). If set lower than the max thread count, it becomes the bottleneck.

server.tomcat.accept-count

(default 100) controls the backlog of pending connections.

Switching to Undertow

Changing the Maven dependency to Undertow replaces Tomcat. In the same demo, Undertow creates a thread pool with both core and max size equal to

CPU_COUNT * 8

. On a 6‑core machine this yields 48 threads:

corePoolSize = 48

maximumPoolSize = 48

queue length = Integer.MAX_VALUE

The numbers come from Undertow’s

EnhancedQueueExecutor

and the constant

WORKER_TASK_CORE_THREADS

derived from the CPU count.

Effect of @Async

Adding

@Async

introduces a separate thread pool whose default core size is 8, reducing the concurrent request handling capability to 8 unless the pool is reconfigured.

Takeaways

When asked how many requests a SpringBoot app can handle, first identify the embedded container (Tomcat, Jetty, Netty, Undertow) and its default thread‑pool settings. Then consider any custom configuration such as

max-connections

or custom

@Async

pools. Clarifying these details lets you give a precise, interview‑ready answer.

JavaPerformancethreadpoolSpringBootTomcatUndertow
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

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