How Many Requests Can a Default SpringBoot App Handle? Uncover Tomcat & Undertow Thread Pool Secrets
This article explores the interview question of how many concurrent requests a SpringBoot project can process by building a minimal demo, measuring Tomcat and Undertow thread pool limits, analyzing default configurations, and showing how container settings and annotations like @Async affect the actual request capacity.
This article tackles the interview question: "How many requests can a SpringBoot project handle simultaneously?" It starts by emphasizing the need to ask clarifying questions about the project's purpose, configuration, web container, and expected response times before answering.
To find an answer, a minimal SpringBoot demo is created with SpringBoot version 2.7.13, containing only two dependencies and two classes: a TestController with a getTest endpoint that sleeps for one hour, and an empty application.properties. The purpose is to occupy a request thread so the total number of usable threads can be observed.
@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 test program repeatedly creates 1,000 threads that call the /getTest 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 shows that, with default settings, the application can handle 200 concurrent requests. This number comes from Tomcat’s default thread pool: core pool size 10, maximum pool size 200, and an effectively unlimited queue (Integer.MAX_VALUE). Tomcat differs from the JDK thread pool by using the maximum pool size as soon as the core threads are busy, bypassing the queue.
Thread dumps confirm that the processing threads belong to Tomcat (e.g., org.apache.Tomcat.util.threads.ThreadPoolExecutor$Worker). Examining Tomcat’s TaskQueue implementation reveals the logic that decides when to enqueue a task or create a non‑core thread, ultimately allowing up to 200 threads to run concurrently.
The server.tomcat.max-connections property can further limit concurrency. Its default value (8192) is larger than the thread pool, so it does not affect the 200‑thread limit. Setting it to 10 reduces the concurrent request count to 10, as demonstrated by the logs.
Other containers behave differently. Switching the embedded container to Undertow (by changing Maven dependencies) changes the default concurrency to 48, which equals CPU cores × 8 (e.g., 6 CPUs → 48 threads). Undertow uses EnhancedQueueExecutor with core and max pool sizes both set to this value, and an unlimited queue.
Adding the @Async annotation introduces another thread pool (default core size 8), which reduces the observable concurrent request count to 8 in the same test.
The article concludes with practical interview advice: always clarify which web container is used, understand its default thread‑pool settings, and consider configuration properties like max-connections and accept-count. By probing these defaults, candidates can give accurate, context‑aware answers rather than a vague number.
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.
