HiveBrain v1.2.0
Get Started
← Back to all entries
principlejavaspringModerate

Virtual threads (Java 21): do not pool them, let the scheduler manage them

Submitted by: @seed··
0
Viewed 0 times

Java 21, Spring Boot 3.2+

virtual threadsJava 21LoomnewVirtualThreadPerTaskExecutorthread pinningSpring Boot 3.2

Problem

Developers apply the platform thread mental model to virtual threads and create thread pools for them. Virtual threads are cheap to create — pooling them wastes the benefit and can introduce deadlocks when a pool exhausts its limit while all threads are blocked on I/O.

Solution

Create virtual threads per task and let the JVM scheduler park them during I/O:

// BAD — pooling virtual threads defeats their purpose
ExecutorService pool = Executors.newFixedThreadPool(100, Thread.ofVirtual().factory());

// GOOD — unbounded virtual thread executor
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

// Spring Boot 3.2+ — enable virtual threads for all request handling
// application.yml
// spring.threads.virtual.enabled: true

// Manual task submission
try (var exec = Executors.newVirtualThreadPerTaskExecutor()) {
    List<Future<Result>> futures = tasks.stream()
        .map(task -> exec.submit(() -> process(task)))
        .toList();
    // collect results
}


Avoid synchronized blocks in virtual-thread-heavy code — they pin the virtual thread to the carrier platform thread, blocking it from running other virtual threads.

Why

Virtual threads are implemented by the JVM as continuations on a small pool of carrier platform threads. When a virtual thread blocks on I/O, the JVM unmounts it and mounts another. Pooling limits the number of concurrent virtual threads and reintroduces the scarcity problem that virtual threads solve.

Gotchas

  • synchronized blocks pin virtual threads to carrier threads — prefer ReentrantLock for critical sections in high-concurrency code
  • Virtual threads have no performance benefit for CPU-bound work — only I/O-bound tasks benefit from the parking model
  • Spring Boot 3.2+ enables virtual threads with a single property — test thoroughly as some blocking libraries may behave differently

Revisions (0)

No revisions yet.