Virtual Threads in Java 21+: Use Cases, Scheduling Boundaries, and Migration
Baseline: Java 21 LTS. Recheck the virtual thread implementation and structured concurrency APIs in Java 24/25 against your target JDK.
1. Where They Fit
Virtual threads are a good fit for workloads with many tasks that block on network, file, or database I/O. When a virtual thread blocks, it can be unmounted, leaving platform threads free to run other tasks.
They do not give CPU-intensive tasks more computing power or increase the capacity of database connection pools, remote services, or thread-safe collections.
2. Minimal Usage
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
Future<Response> future = executor.submit(() -> client.fetch(request));
Response response = future.get();
}
Do not submit work to virtual threads when the downstream call chain is unbounded. Use a Semaphore, connection pool, and request budget to cap concurrency.
3. Migration Checklist
Check whether ThreadLocal storage contains large objects, whether blocking calls can actually unmount the carrier, whether synchronized critical sections, lock contention, JNI, or native blocking are present, and whether cancellation and timeouts propagate.
JDK 21-era pinning diagnostics are still worth keeping. After upgrading to the target JDK, reread the relevant JEPs and release notes, and do not treat a version-specific internal implementation as an API guarantee.
4. Comparison with Async APIs
Virtual threads let synchronous, blocking code run at a lower thread cost, while async APIs avoid blocking through explicit continuations or event loops. Choose based on your team's concurrency model, library compatibility, debugging approach, and downstream capacity—not just the thread count.
5. Benchmarking
Use the same connection pool, timeout settings, workload, and downstream service to benchmark platform threads, virtual threads, and async implementations separately for throughput, latency, memory use, cancellation, and failure recovery. Do not use CPU-intensive benchmarks to draw conclusions about I/O.