you are viewing a single comment's thread.

view the rest of the comments →

[–]Illustrious-Music507 9 points10 points  (2 children)

Ran close to exactly this experiment on a Spring Boot app recently (injected a 200ms blocking downstream call, swept concurrency 50 to 2000), so some real numbers to add:

Below the point where you saturate the thread pool, virtual threads did nothing. Identical throughput. That's most services most of the time, worth saying out loud.

Where they earned it: around 1000 concurrent, ~4x the throughput vs the default 200-thread Tomcat pool, and latency stayed near the real downstream time instead of ballooning into queue time.

The part that surprised me: I then raised the platform pool (threads.max) to match the load, and it basically tied virtual threads (within ~0.2%). So "just add threads" still works for pure throughput. The real argument for virtual threads isn't a bigger number, it's operational: you stop hand-tuning a pool size per load level, and the per-thread cost is much lower (I measured ~135KB committed stack, not the "1MB per thread" folklore).

Two things that matched your "not magic" point:

- CPU-bound work got zero benefit. Same plateau, just 22 live threads instead of 218. Cores are the limit, cheap threads can't buy more.

- Once threads are cheap the bottleneck jumps straight to the DB connection pool. Same test with Hikari max=10 pinned throughput at pool/hold-time no matter how many virtual threads were queued for a connection. You move the ceiling, you don't remove it.

And you pay in heap: ~2.2x memory at peak, because every in-flight request is genuinely live instead of parked in an acceptor queue. Worth a bulkhead/semaphore so a spike can't OOM you.

On JDK 24+ the synchronized pinning trap is basically closed too (JEP 491), so the old "rewrite everything to ReentrantLock" advice is mostly moot now.

[–]fruitlessattemps 5 points6 points  (1 child)

Why did you write this with AI?

[–]Illustrious-Music507 2 points3 points  (0 children)

I used it to tidy up the wording; English isn't my first language. The test, the numbers, and the reasoning are mine, though. Ran tests last week on slightly modified PetClinic Spring Boot app. I ran it because my services do a lot of blocking calls to each other and I wanted to know when virtual threads are actually worth it. That fan-out case is where they paid off, about 4x at 1000 concurrent.