79

I'm trying to understand Spring WebFlux. The things I've found so far are reactive at the core, no Servlet API, no thread per request, HTTP 2, server pushes, application/stream+json.

But what is the difference between asynchronous calls in Spring MVC? I mean in Spring MVC when you return Future, DefferedResult and etc you get logic in the request handler (controller method) executed in a separate thread, so you can benefit from saving thread pool resources for dispatching requests as well.

So could you please highlight differences related to that? Why WebFlux is better here?

Thank you for your time very much!

6
  • 5
    Reactive programming is push driven and uses a single dispatcher thread (which is highly efficient) whereas the old model is still limited to the number of threads in your thread pool. Commented Oct 6, 2017 at 12:59
  • @M. Deinum But in this case I'm limited with load one thread can handle. Why not to use several of them, not just one having multicore system? Commented Oct 6, 2017 at 13:02
  • 2
    It is an event dispatcher thread it is an entirely different model. It only dispatches events (very quickly) whereas the other model is still blocking. Commented Oct 6, 2017 at 13:05
  • @M. Deinum ok, that is very interesting, I'm sure I should take a look at it, thank you! Commented Oct 6, 2017 at 13:08
  • @M. Deinum, please share request lifecycle Commented Jun 4, 2019 at 12:53

3 Answers 3

56

The Servlet async model introduces an async boundary between the container threads (1 Servlet request/thread model) and the processing of the request in your application. Processing can happen on a different thread or wait. In the end, you have to dispatch back to a container thread and read/write in a blocking way (InputStream and OutputStream are inherently blocking APIs).

With that model, you need many threads to achieve concurrency (because many of those can be blocked waiting for I/O). This costs resources and it can be a tradeoff, depending on your use case.

With non-blocking code, you only need a few threads to process a lot of requests concurrently. This is a different concurrency model; like any model, there are benefits and tradeoffs coming with it.

For more information about that comparison, this Servlet vs. Reactive stacks talk should be of interest.

Sign up to request clarification or add additional context in comments.

11 Comments

From my understanding, another benefit would be what's in the response itself. A Publisher (Flux/Mono) is considered more "advanced" than a Future, as it gives more control on the flow, e.g backpressure etc.
Could you eleborate? Even for reactive webFlux we have to wait writing to socket. As I understand in case of Asyc servlet api Container thread have to pass request into application threadPool to await free worker and after passing the thread becomes free and can be reused for another requests just after passing that request. Why do you say that With that model, you need many threads to achieve concurrency ?
@gstackoverflow We sometimes need to wait to write/read to a socket, but in a non-blocking manner - in that case, no thread is sitting idly during that time. With the Servlet 3.0 model, the number of server threads is proportional to the number of max concurrent requests. Please watch the talk I pointed to, this is all explained there in great details.
Sorry, it is not clear for me. In case of DefferedResult Tomcat thread just passes request to application threadPool - it is so short operations and thus it is ready to handle another request. Which killer feature webFlux provides?
According to your answer I understand that your concern about DefferedResult contains in that phrase: In the end, you have to dispatch back to a container thread and read/write in a blocking way (InputStream and OutputStream are inherently blocking APIs). Do you want to say that WebFlux has some magic sockets which can read/write asyncronously ? Is it possible?
|
13

Servlet API is blocking I/O which requires 1 thread per HTTP request. Spring MVC async relies on Servlet APIs which only provides async behavior between container threads and request processing threads but not end to end.

Spring WebFlux on the other hand achieves concurrency by a fixed number of threads by using HTTP sockets and pushing chunks of data at a time through the sockets. This mechanism is called event loop, an idea made popular by Node.js. Such an approach is scalable and resilient. Spring 5's spring-webflux uses the event loop approach to provide async behavior.

More can be read from

Comments

1

Just an update on this topic in November 2024 to say Java JDK 21 now has released the concept of Virtual Thread.

Java threads are basically a wrapper for OS threads, and are known as platform threads. Therefore, threads are scarce resources, and therefore very valuable. If they are scarce, they are consequently expensive to have in abundance — approximately 2MB of memory is the cost to create a new thread.

Basically, we can say that threads are the “little place” where our code is executed.

Virtual thread

Forget all about threads being expensive and scarce resources. Virtual threads solve the problem of wasting time on threads, through a paradigm called coroutines. Virtual threads are still threads, and they act like threads, with the difference that they are no longer managed by the OS, like platform threads, but by the JVM. Now, for each platform thread, we will have an associated pool of virtual threads. How many virtual threads for each platform thread? As many as necessary. Each JVM can have millions of virtual threads.

With Java 21 and Spring Boot 3.2+, all you need is a parameter in application.properties

spring.threads.virtual.enabled=false

And your application will already be using virtual threads!

Before, there was a platform thread for each request. Now, for each task that needs to be executed, the platform thread will delegate this task to a virtual thread.

Instead of the platform thread itself executing the request, it delegates it to a Virtual Thread, and when this execution encounters blocking I/O, Java suspends this execution by placing the virtual thread context in the heap memory, and the platform thread is free to execute new tasks. As soon as the virtual thread is ready, it resumes execution.

Virtual threads are daemon threads, so they do not prevent the application from shutting down, unlike non-daemon threads in which the application ends when the thread ends.

Never use a pool

When we talk about thread pools or connection pools, we are implicitly saying: I have a resource that is limited, so I need to manage its use. But virtual threads are abundant, and a virtual thread pool should not be used.

The number of virtual threads we will have is equal to the number of simultaneous activities we execute. In short, for each simultaneous task you must instantiate a new virtual thread.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.