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.
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
TestControllerappear 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.ThreadPoolExecutorand its
corePoolSizeand
maximumPoolSizevalues.
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
EnhancedQueueExecutorand the constant
WORKER_TASK_CORE_THREADSderived from the CPU count.
Effect of @Async
Adding
@Asyncintroduces 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-connectionsor custom
@Asyncpools. Clarifying these details lets you give a precise, interview‑ready answer.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.