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:
@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);
}
}A load‑test class spawns many threads that call the endpoint:
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();
}
}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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
