Spring Boot Concurrency Explained: Multiple Requests to One Controller

 

Introduction

When building Spring Boot applications, a common question developers ask is:
"What happens when multiple requests hit the same controller at the same time?"

In this article, we’ll dive deep into how Spring Boot handles concurrent requests, what happens under the hood, and how you can design controllers that are both efficient and thread-safe.


1. The Lifecycle of a Controller in Spring Boot

By default, Spring Boot creates controllers as singleton beans.

  • Only one instance of the controller exists in the application context.

  • That single instance can handle multiple concurrent requests — thanks to the thread-per-request model used by the servlet container (Tomcat, Jetty, or Undertow).


Diagram 1 – Request Flow to a Singleton Controller

java
Multiple HTTP Requests │ │ │ ▼ ▼ ▼ ┌─────────────────────────────┐ │ Servlet Container (Tomcat) │ └─────────────┬───────────────┘ │ Each request gets its own thread │ ▼ ┌─────────────────────────────┐ │ Singleton Controller │ └─────────────────────────────┘

2. Thread-per-Request Model

Here’s how concurrent requests are processed:

  1. The HTTP request arrives at the server.

  2. The servlet container assigns a separate thread from its thread pool to handle the request.

  3. The request is mapped to the appropriate controller method by the DispatcherServlet.

  4. The method executes independently on that thread, then returns a response.

Tomcat default configuration:

  • maxThreads = 200 → up to 200 requests can run in parallel.

  • Any extra requests wait in a queue until a thread is free.


Diagram 2 – Multiple Threads Calling the Same Controller

scss
Thread-1 → Controller method() Thread-2 → Controller method() Thread-3 → Controller method() ... all running on the same controller instance

3. Thread Safety Concerns

Since there’s only one instance of the controller:

  • Avoid mutable instance variables that can be modified during a request.

  • Use method-local variables or immutable objects for request-specific data.

Thread-unsafe example:

java
@RestController public class CounterController { private int counter = 0; // Shared mutable state @GetMapping("/count") public int increment() { counter++; // Race condition risk return counter; } }

Thread-safe example:

java
@RestController public class CounterController { @GetMapping("/count") public int increment() { int counter = 0; // Local variable counter++; return counter; } }

4. Key Takeaways

  • Spring Boot controllers are singleton by default.

  • Multiple requests are handled concurrently using separate threads.

  • Controllers must be stateless or carefully manage shared state.

  • Use local variables for request-specific data to ensure thread safety.


Diagram 3 – Safe Controller Design

pgsql
Singleton Controller │ ├── No shared mutable fields └── All request data stored in method-local variables

Conclusion

Understanding how Spring Boot processes multiple requests is essential for writing scalable, thread-safe, and reliable applications.
By following these practices, you ensure your controllers can handle high concurrency without race conditions or data corruption.

Post a Comment

0 Comments