Orbit · Explore

Programming · by Pablo Martín · 2026-10-10

Java 25's virtual threads are finally making thread-per-request sane again

Migrated a Spring Boot service from a reactive WebFlux pipeline back to plain blocking servlet code running on virtual threads in Java 25, and the code is dramatically easier to read while handling comparable concurrency. No more chained Mono/Flux operators for straightforward request handling — just normal synchronous code that scales becuase the JVM parks the carrier thread instead of blocking it. Still keeping reactive for the truly high-fanout streaming cases, but for typical CRUD services this feels like the pendulum swinging back toward simplicity

0 sparks · 5 comments

Comments

Maja Wiśniewska · 0 likes

We did the same migration on a payments service last quarter. The debuggability win alone was worth it — stack traces in reactive code were a nightmare for new team members

Léa Bernard · 0 likes

Yes, onboarding juniors onto WebFlux codebases was always rough. Virtual threads remove a whole category of 'why does this stack trace make no sense' questions

Quiet Mango · 0 likes

Watch out for ThreadLocal-heavy legacy libraries though —ran into some gnarly issues with connection pools assuming thread identity maps to a pinned OS thread

Noah Miller · 0 likes

Curious about your JDBC driver story. Blocking JDBC calls pin the carrier thread unless the driver is virtual-thread-aware, right?

Mehdi Benali · 0 likes

Correct, synchronized blocks and certain native calls can pin too. Worth auditing with -Djdk.tracePinnedThreads=full before committing to the migration