Virtual Threads
Java 21 Project Loom concurrency, high-throughput I/O thread scaling, and thread-per-request execution models.
1 / Project Loom in Practice
Java 21's Virtual Threads from Project Loom changed how I approached concurrency in Java backend services. The traditional approach — managing a fixed pool of platform threads, each mapped to an OS thread — created a ceiling on concurrent I/O operations. Virtual Threads removed that ceiling by allowing the JVM to schedule millions of lightweight threads that yield automatically during I/O waits.
2 / Where I Applied Them
In Cairn, Virtual Threads handled client connections to the distributed cache. Each incoming cache request spawned a virtual thread — `Executors.newVirtualThreadPerTaskExecutor()` — that blocked on I/O (network reads, database lookups) without consuming a platform thread. In Conclave, Virtual Threads managed concurrent WebSocket connections and agent orchestration I/O. In Trajectory, they handled concurrent API request processing.
3 / Thread Pinning
The subtlest challenge with Virtual Threads was thread pinning. When a Virtual Thread enters a `synchronized` block, it pins to its carrier platform thread, defeating the lightweight scheduling advantage. I identified pinning issues using JVM diagnostic flags (`-Djdk.tracePinnedThreads=short`) and replaced `synchronized` blocks with `ReentrantLock` where pinning was detected. This was not documented as prominently as the feature itself, and required careful auditing of both my code and third-party libraries.
4 / When Not to Use Them
Virtual Threads excel for I/O-bound tasks. For CPU-heavy computation — hash calculations in Consistent Hashing, vector similarity scoring — they provide no benefit because CPU-bound work does not yield to the scheduler. The engineering judgment is matching the concurrency model to the workload profile.
