10

In my Spring Boot 2.1.6 project (based on Tomcat) I have a rest controller. I added a default constructor to it which prints something. I thought in Tomcat-based servers each request is handled in separate thread. So I expected each request to trigger a new controller object and as a result new print from the constructor. However, I made a test of sending 30 requests to the rest controller and I only see that the print was made once. So as far as I understand the rest controller handles all those requests in one thread.

My question is whether indeed multiple requests are handled in a single thread or maybe there's certain request threshold upon which another thread will be opened? I'm using default Spring Boot configuration perhaps this is controlled somewhere in the config?

This is the code for my controller:

@RestController
public class TrackingEventController {

    public TrackingEventController() {
        System.out.println("from TrackingEventController");
    }

    @RequestMapping(method=GET, path=trackingEventPath)
    public ResponseEntity<Object> handleTrackingEvent(
            @RequestParam(name = Routes.event) String event,
            @RequestParam(name = Routes.pubId) String pubId,
            @RequestParam(name = Routes.advId) String advId) {

        return new ResponseEntity<>(null, new HttpHeaders(), HttpStatus.OK);
    }
}
hitchhiker
  • 1,099
  • 5
  • 19
  • 44
  • 2
    It depends on your set up. But _most likely_ there's a pre-initialized _pool_ of threads and one is drawn from that in order to handle the request. So a single thread can (and hopefully is) reused repeatedly, but _concurrent_ requests will be handled by different threads. – BeUndead Aug 02 '19 at 09:39
  • 1
    It's not a "controller per thread". Your controller is likely a singleton, created by Spring once and reused for requests. If you want a controller per request, you should scope the controller component appropriately. – M. Prokhorov Aug 02 '19 at 09:39
  • 1
    Not an answer, and although not terrible in Spring Boot, you should get into the habit of using `logger.info()` instead of `System.out.println()` in any code where logs are at all important. I use IntelliJ and have rebound the default `System.out.println()` bind to `logger.info` to enforce this – cameron1024 Aug 02 '19 at 09:42

2 Answers2

16

You're mixing two orthogonal concepts:

  1. a thread
  2. a controller instance

A single thread could create and/or use one, or several controller instances.

Multiple threads could also create and/or use one, or several controller instances.

The two are unrelated.

And how it actually works is

  • Spring beans are singletons by default, so Spring creates a single instance of your controller
  • A servlet container uses a pool of threads.
  • Every time a request comes in, a thread is chosen from the pool, and this thread handles the request. If the request is mapped to your controller, then the appropriate method of the unique controller instance is executed by this thread.

If you want to know which thread is handling the current request, add this to your controller method:

System.out.println(Thread.currentThread().getName());
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • 3
    So if multiple threads may be accessing the same singleton controller it is my job to synchronize the code inside the controller right? But the more synchronization I add the less benefit will I reap of thread per request model. What is the best practice there? – hitchhiker Aug 02 '19 at 10:16
  • 4
    Yes and no. If the controller really has mutable state, yes. If not, which is (or at least should be) the case most of the time, and is the case in the example you posted, then synchronizing is useless. – JB Nizet Aug 02 '19 at 10:18
1

Spring boot Tomcat thread pool default size is 200. You can make out that different threads server different requests. Put a debug point on some REST endpoint, and call it multiple times from Postman etc. From debugger, check the thread name. s.b.

enter image description here

Apurva Singh
  • 4,534
  • 4
  • 33
  • 42