Lesson 21: Virtual Threads (Project Loom) – Java 19+

Java 19 introduced Virtual Threads, also known as Project Loom, which provides a lightweight alternative to traditional threads. This feature allows Java to handle millions of concurrent tasks efficiently without the overhead of platform (OS) threads.


1. What Are Virtual Threads?

Virtual Threads (Thread.ofVirtual()) are lightweight user-mode threads.
Java can create millions of Virtual Threads without blocking OS resources.
Each Virtual Thread is managed by the JVM, not the OS.
Ideal for high-concurrency applications (e.g., web servers, APIs, and real-time processing).


2. Traditional Threads vs. Virtual Threads

🔴 Before Java 19 (Traditional Platform Threads)

  • Each Java thread is mapped to an OS thread, limiting scalability.
  • Creating too many threads (new Thread()) is expensive.
  • Blocking operations (sleep(), wait(), IO) waste OS resources.

🟢 Java 19+ (Virtual Threads Are Lightweight!)

  • Thousands (or millions) of Virtual Threads can run on a few OS threads.
  • More efficient for blocking tasks (e.g., database calls, network requests).

📌 Example: Creating a Virtual Thread

public class Main {
    public static void main(String[] args) throws Exception {
        Thread vThread = Thread.ofVirtual().start(() -> System.out.println("Hello from a Virtual Thread!"));

        vThread.join(); // Wait for the Virtual Thread to finish
    }
}

Output:

Hello from a Virtual Thread!

Runs like a normal thread but is much lighter!


3. Running Multiple Virtual Threads (Millions of Them!)

📌 Example: Launching 1 Million Virtual Threads

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        IntStream.range(0, 1_000_000).forEach(i ->
            Thread.ofVirtual().start(() -> System.out.println("Thread: " + i))
        );
    }
}

Output:

Thread: 0
Thread: 1
Thread: 2
...
Thread: 999999

No OS slowdown! Virtual Threads allow massive concurrency.


4. Virtual Threads and Executors (Executors.newVirtualThreadPerTaskExecutor())

📌 Example: Using a Virtual Thread Executor

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
            for (int i = 0; i < 1000; i++) {
                executor.submit(() -> System.out.println(Thread.currentThread()));
            }
        }
    }
}

Output (Threads are dynamically created and destroyed):

VirtualThread[#5]/runnable
VirtualThread[#6]/runnable
VirtualThread[#7]/runnable
...

No need to manage thread pools manually!


5. When Should You Use Virtual Threads?

🚀 Use Virtual Threads when:
✔ You need massive concurrency (thousands or millions of tasks).
✔ You perform blocking operations (e.g., database queries, HTTP requests).
✔ You want a lightweight alternative to traditional threads.

🚨 Do NOT use Virtual Threads when:
❌ You perform heavy CPU computations (Use traditional ForkJoinPool instead).
❌ Your tasks need fine-grained thread control.


6. Comparison: Before Java 19 vs. Java 19+ (Virtual Threads)

FeaturePlatform Threads (new Thread())Virtual Threads (Thread.ofVirtual())
Thread ManagementHandled by OSHandled by JVM
Thread CostHigh (OS thread per Java thread)Low (millions of Virtual Threads possible)
Best ForCPU-bound tasksIO-bound tasks (HTTP, DB)
BlockingWastefulLightweight and efficient

Lesson Reflection

  1. How do Virtual Threads improve scalability in Java applications?
  2. Why are Virtual Threads better for IO-bound tasks rather than CPU-bound tasks?
  3. Can you think of a real-world scenario where Virtual Threads would be useful?

Answers to Reflection Questions on Virtual Threads (Java 19+)


1️⃣ How do Virtual Threads improve scalability in Java applications?

Traditional Java threads are mapped to OS threads, which are heavy and limited.
Virtual Threads (Thread.ofVirtual()) are managed by the JVM, allowing millions of them to exist efficiently.
Virtual Threads are lightweight, making them ideal for high-concurrency applications like web servers, APIs, and databases.

📌 Example: Handling 1 Million Requests Efficiently
🔴 Before Java 19 (Platform Threads, Expensive!)

ExecutorService executor = Executors.newFixedThreadPool(100);
for (int i = 0; i < 1_000_000; i++) {
    executor.submit(() -> {
        Thread.sleep(1000); // Simulate I/O operation
        System.out.println("Request handled");
    });
}
executor.shutdown();

Problem: Limited by the number of OS threads (100 in the pool).

🟢 Java 19+ (Virtual Threads, Scales to Millions!)

try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 1_000_000; i++) {
        executor.submit(() -> {
            Thread.sleep(1000); // ✅ Non-blocking with Virtual Threads
            System.out.println("Request handled");
        });
    }
}

Handles 1 million requests without performance issues!

Virtual Threads improve scalability by handling many more concurrent tasks efficiently.


2️⃣ Why are Virtual Threads better for IO-bound tasks rather than CPU-bound tasks?

🚀 Virtual Threads are designed to handle tasks that spend time waiting (I/O-bound).

I/O-Bound Tasks (Good Use Case for Virtual Threads)

  • Reading/writing to a database.
  • Making HTTP API calls.
  • Handling user requests in a web server.

Example: Making HTTP Calls Concurrently

try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 1000; i++) {
        executor.submit(() -> {
            // Simulate an HTTP request
            Thread.sleep(1000);
            System.out.println("HTTP request completed");
        });
    }
}

Since Virtual Threads don’t block OS threads, they work well with slow I/O operations.


CPU-Bound Tasks (Not Good for Virtual Threads)

  • Processing large datasets.
  • Performing complex calculations (AI, Machine Learning).
  • Rendering graphics.

🔴 Example: Heavy CPU Computation (Better with ForkJoinPool)

ExecutorService executor = Executors.newFixedThreadPool(10); // Better for CPU tasks
for (int i = 0; i < 100; i++) {
    executor.submit(() -> {
        long result = 0;
        for (long j = 0; j < 1_000_000_000; j++) { result += j; } // Heavy computation
        System.out.println("Computation done: " + result);
    });
}
executor.shutdown();

For CPU-heavy tasks, traditional threads work better because they map to real CPU cores.


3️⃣ Can you think of a real-world scenario where Virtual Threads would be useful?

🚀 Example 1: Handling High-Traffic Web Servers (Millions of Concurrent Requests)
✔ A web server that handles millions of users (e.g., Twitter, Facebook).
✔ Virtual Threads allow each request to have its own thread without OS limits.

🚀 Example 2: High-Concurrency Databases
✔ A banking system processing millions of transactions.
✔ Virtual Threads allow efficient database query execution.

🚀 Example 3: Chat Applications (WhatsApp, Discord, Slack)
Each user connection runs in a Virtual Thread, reducing memory usage.

📌 Example: Building a Scalable Web Server

import java.util.concurrent.*;

public class WebServer {
    public static void main(String[] args) {
        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
            for (int i = 0; i < 1_000_000; i++) {
                executor.submit(() -> {
                    Thread.sleep(500); // Simulate user request processing
                    System.out.println("Handled user request");
                });
            }
        }
    }
}

Handles 1 million requests efficiently!

Virtual Threads shine in scenarios where high concurrency is needed, but CPU work is minimal.


🔍 Key Takeaways

Virtual Threads scale better than traditional threads by reducing OS overhead.
They are best for I/O-bound tasks (database calls, API requests, etc.).
They are NOT ideal for CPU-intensive tasks (use ForkJoinPool instead).
Real-world use cases include web servers, chat apps, and high-concurrency systems.

The next Java 21+ feature: Scoped Values (ScopedValue for thread-local data sharing) 😊🚀

Java Sleep