Stage 8: Concurrency and the JVM, lesson 5 of 7

Virtual threads

Advanced3 min read@since 21Code runs on your Java 25
Explain it forThe essentials plus production detail and pitfalls.

Virtual threads (final in Java 21, from Project Loom) are lightweight threads managed by the JVM rather than the operating system. When a virtual thread blocks on I/O, the JVM parks it and frees the underlying carrier thread for other work.

Why it matters: the simple thread-per-request style (blocking JDBC, RestClient) now scales to hundreds of thousands of concurrent requests without reactive code.

  • Create one with Thread.ofVirtual().start(...) or Executors.newVirtualThreadPerTaskExecutor().
  • In Spring Boot 3.2+, set spring.threads.virtual.enabled=true.
  • Don't pool virtual threads; create one per task.
  • They help I/O-bound work. CPU-bound work gains nothing.

Example

Java
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    List<Future<String>> results = IntStream.range(0, 10_000)
        .mapToObj(i -> executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));    // blocking is fine here
            return "task " + i;
        }))
        .toList();
    System.out.println(results.getLast().get());    // about 1 second in total, not 10,000
}

Common mistake

Putting virtual threads in a fixed-size pool, or expecting CPU-heavy work to run faster. They increase how many tasks can wait at once, not raw computing speed.

Under the hood

Virtual threads are cheap because their stacks live on the heap as small, growable chunks. Watch for: blocking inside synchronized pinned the carrier before Java 24 (JEP 491 fixed it); ThreadLocal with large objects multiplies memory across millions of threads, so prefer scoped values (final in Java 25). Downstream limits still apply: 10,000 virtual threads will happily exhaust a 10-connection database pool, so guard scarce resources with a Semaphore.

Check yourself

Should you pool virtual threads?

How this connects

Where this leads

You've reached the end of this thread. Try a learning path for what's next.

Part of Crack the Java interview, Upgrade from Java 8 to Java 25, Microservices and production.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.