Urgent.News

One page, thousands of outlets. See who else covered it.

Editions โ–พ

Tech

Virtual threads didn't scale your app. They just moved the crash to your database.

When Java 21 was released with virtual threads, everyone celebrated, including myself. Then someone's app fell over at 2AM. And the crash wasn't where anyone expected. ๐Ÿ˜… The promise everyone heard Project Loom introduced Virtual threads in Java 21, which made it possible to create a large number of threads effortlessly. You also don't need to fine-tune the thread pools on your platform. Theโ€ฆ

When Java 21 arrived with virtual threads, many people were excited, including the author. However, shortly after, an application crashed at 2 AM, and the issue was not where anyone anticipated. Java 21 introduced Project Loom, which brought virtual threads to Java, allowing developers to create a large number of threads without the need to fine-tune thread pools.

The idea was simple: write blocking code and make it perform like asynchronous code. With the addition of Thread.ofVirtual(), developers witnessed a significant increase in throughput. The celebration, however, overlooked a crucial fact.

The ability to handle 10,000 requests simultaneously was impressive, but the database was not prepared for the sudden surge. Connection pools, like HikariCP, have a fixed size optimized for previous scenarios when platform threads limited concurrency. Virtual threads no longer acted as the bottleneck; hence, if 10,000 requests all competed for resources and reached the pool of only 20 connections, that pool became the new choke point.

Unfortunately, the remaining 9,980 users had to wait in line or give up altogether. The speed of the application did not increase; instead, the load was distributed to a fixed resource pool.

The underlying issue is that compute concurrency is free, but resource concurrency remains finite. Removing a bottleneck upstream shifts it downstream. A fixed pool behind infinite threads is essentially a queue with additional steps. The problem is that your database, APIs, and file handles are all running out of resources, regardless of the number of virtual threads you can spawn. Renovating both layers requires a new perspective. The pool is no longer a detail to overlook but the very ceiling that limits performance.

Here are some crucial considerations: size the connection pool based on what the database can survive, not what the application wants to send; add explicit backpressure to fail requests quickly instead of silently piling up; monitor pool wait time rather than just request throughput; and treat every finite downstream resource as its own concurrency budget.

Virtual threads have undoubtedly brought significant improvements, but they are not a simple scale button. They reallocate load and place it where fixed resource pools exist. Before implementing a Loom rollout, it's essential to ensure that the HikariCP max size is ready for the party. The real question is whether virtual threads have merely moved the bottleneck downstream or if they have prompted a redesign of the resource layer to match.

Written by urgent.news from Dev.to's reporting โ€” not their text. Machine-written โ€” may contain errors; check the original before relying on it.

Read the original at dev.to โ†’

More in Tech

More from Monday 17 August โ†’