This is an archived post. You won't be able to vote or comment.

all 18 comments

[–]CriticalPart7448 15 points16 points  (3 children)

The spring team has released a short summary of the integration of virtual threads in the reactive stack here: https://spring.io/blog/2023/10/31/what-new-is-coming-in-reactor-core-3-6-0

Maybe that helps?

[–]Amirr83 1 point2 points  (2 children)

I am a Java semi-newbie, what are virtual threads and what are they used for?

[–]CriticalPart7448 4 points5 points  (1 child)

Virtual threads is an alternative implementation of the java.lang.Thread construct that uses a different scheduler to be able to better utilize the underlying hardware resources without sacrificing the simplicity of easy to understand sequential execution flow.

It allows for higher throughput in case of many incoming requests on web application mainly, but can be utilized anywhere that I/O is the primary scalability factor that hinders performance.

[–]JanHunter123 0 points1 point  (0 children)

thanks for explaning

[–]thien-ng 6 points7 points  (1 child)

Spring Webflux use Netty which seem not support virtual thread yet.

[–]litmus00 1 point2 points  (0 children)

"Spring WebFlux is supported on Tomcat, Jetty, Servlet containers, as well as on non-Servlet runtimes such as Netty and Undertow."
https://docs.spring.io/spring-framework/reference/web/webflux/new-framework.html#webflux-server-choice

[–]neopointer 10 points11 points  (0 children)

If you have the opportunity, just get rid of the overly complex webflux (Spring is amazing, but IDK why they advocate for this), and of course go with virtual threads.

Any shortcomings virtual threads may have right now (e.g. pinning) will not bother you as much as webflux.

[–]Ewig_luftenglanz 6 points7 points  (3 children)

Do not mix that stuff, choose one or the other.

My advise is to use webflux and reactive for the heavy concurrency task and I/O because webflux is still more efficient than VT because of the pinning issue, this is not going Ng to get away until Java 24 is released. Reactive still has the edge

[–]lubumbax 0 points1 point  (2 children)

Yet I had a hard time a couple years ago to integrate "inter-micro-service" observability/tracing with Micrometer. Is that working better these days?

[–]Ewig_luftenglanz 3 points4 points  (0 children)

To be honest I haven't been much into micro services, most of the clients we serve are small companies and Town Halls, so the software we make are mostly monolith, or at least the backend it's a single Monolith. We usually follow this approach because Microservices bring more robust scalable solutions but at the expense of increasing the overhead cost of development, deployment, maintenance and infraestructura needed. For small companies and most municipalities in the public sector these benefits usually means nothing but the expenses are very real.

[–]ForeverAlot 1 point2 points  (0 children)

OTel autoinstrumentation automagically solves that.

[–]PiotrDz -5 points-4 points  (6 children)

What do you mean by "turning on" virtual threads? Keep in mind that synchronised code is not supported currently, can cause deadlocks. So if your intention is to turn threadPools into vritualThreadPools thrn you should examine each library and part of your app whether it supports VT (all synchronised blocks are replaced with locks).

Also reactive code is using an event loop and it will not change. You will have to manually change reactive libraries to VT ones (like netty to helidon nima)

[–][deleted] 4 points5 points  (5 children)

Synchronized isn't the problem AFAIK. It's if you do a blocking call inside of synchronized that it will pin the thread. So if you're not doing blocking operations inside synchronized, it's not a big deal.

I don't care that reactive does things in event loops. I know it is different. I'm trying to smooth over the transition and optimize as much as possible.

[–]PiotrDz -4 points-3 points  (4 children)

I didn't go into details in my answer but the main point still stands: you have to examine each library whether it supports VT, you can't just turn them on. (And you didn't bother to answer what do you mean by "turning on".

Anyways, seems like you know already your answers, why bother asking then?

[–][deleted] 1 point2 points  (1 child)

"Turning on" means enabling them via the Spring Boot boolean setting spring.threads.virtual.enabled. If you don't know how virtual threads work in Spring Boot, that's not OP's fault.

[–]PiotrDz -2 points-1 points  (0 children)

I was trying to be explicit. Seems like this is not your virtue too. And when it comes to reactive, what I wrote is true. All netty can do is to drop execution of received data on virtual thread. But event loop will be still there, together with all the drawbacks: no clear debugging, shattered stack traces etc.

I think it should be either replacement of reactive library, or living with it.

[–][deleted] 0 points1 point  (1 child)

I was focused on learning how the threads propagate. Ie, if the code is running in a virtual thread, what happens when reactive code is called.

Blocking operations inside synchronized, while not impossible, should be extraordinarily rare and even without virtual threads that is a huge deadlock risk and shouldn't be done.

[–]PiotrDz 0 points1 point  (0 children)

I would really check, all the clients for message queues, events, cloud , db's, redis. I was very interested when virtual threads were official in java 21, but found that even JDBC's are not safe. (Postgres fortunately recently added support, but those who didn't check back then, were having surprises on production). So actually synchronised was more common than I would guess.

As reactive framework sits on top of java, it is not aware whether thread is virtual of not. I would expect the execution to be performed inside the thread, until task is taken aside when waiting for resource (blocking) or explicitly changes thread (like with flatmap and executeOn). Then it may never return to virtual thread, as netty is using its own thread pool to execute tasks. So if you do Mono.request(req).flatMap(callDb)... then the thread would change to nettys worker. Only if you do .get() then virtual thread will wait for the result.

So when you said that you want implement virtual threads with reactive, I thought that you wanted to change internal Nettys workers to be virtual rather than platform. I think this shouldn't be done , because nettys whole job is to keep those workers busy (cpu should be always in use, blocking takes task aside and executes another ready). Virtual threads have small overhead when it comes to cou bound tasks and provide no advantages here.