Lesson 11 / 39

Virtual Threads (Java 21)

Handle massive concurrency with lightweight virtual threads that make blocking code cheap, and know when platform threads still fit.

Threads that are cheap

A virtual thread is scheduled by the JVM, not the OS, so you can run millions of them. When one blocks on I/O, the JVM parks it and reuses the carrier thread. This keeps the simple thread-per-request style scalable.

Creating virtual threads

Use Thread.ofVirtual() or an executor that starts one virtual thread per task.

Thread.ofVirtual().name("worker-1").start(() -> fetch(url));

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (String u : urls) {
        executor.submit(() -> fetch(u));   // one cheap thread per task
    }
}   // close() waits for all tasks

Virtual threads help I/O-bound work, not CPU-bound loops. Do not pool them, avoid long synchronized blocks around blocking calls, and use ReentrantLock instead.

Quick check

Quick check: What are virtual threads best suited for?

  • Many concurrent blocking I/O tasks
  • CPU-bound number crunching only
  • Replacing the garbage collector
  • Compiling code
Answer

Many concurrent blocking I/O tasks — They make blocking I/O cheap so you can scale thread-per-task code.