GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • java.evolved
  • ←
  • β†’

This view

  • Original page
  • New address

GeezerVison is showing javaevolved.dev β€” Virtual threads | java.evolved

Home / Concurrency / Virtual threads
Concurrency Beginner

Virtual threads

  • πŸ› Report a code issue
  • 🌐 Report a translation issue
  • πŸ’‘ Suggest a new pattern

Create millions of lightweight virtual threads instead of heavy OS threads.

Virtual Threads Concurrency
Code Comparison
βœ• Java 8
Thread thread = new Thread(() -> {
    System.out.println("hello");
});
thread.start();
thread.join();
βœ“ Java 21+
Thread.startVirtualThread(() -> {
    IO.println("hello");
}).join();
Share 𝕏
See a problem with this code? Let us know.
Why the modern way wins
⚑

Lightweight

Virtual threads use KB of memory, platform threads use MB.

♾️

Scalable

Create millions of threads β€” no pool sizing needed.

🧹

Simple model

Write blocking code that scales like async code.

Old Approach
Platform Threads
Modern Approach
Virtual Threads
Since JDK
21
Difficulty
Beginner
JDK Support
Virtual threads
Available

Widely available since JDK 21 LTS (Sept 2023)

How it works

Virtual threads are lightweight threads managed by the JVM, not the OS. You can create millions of them without tuning thread pools. They're ideal for I/O-bound tasks like HTTP calls and database queries.

Related Documentation
Virtual Threads (JEP 444) β†— Thread.ofVirtual() β†—
Proof
View proof source β†—
Related patterns
Concurrency Beginner

Thread.sleep with Duration

Java 8
// What unit is 5000? ms? us?
Thread.sleep(5000);

// 2.5 seconds: math required
Thread.sleep(2500);
Java 19+
Thread.sleep(
    Duration.ofSeconds(5)
);
Thread.sleep(
    Duration.ofMillis(2500)
);
Hover to see modern ➜
JDK 19+ β†’
Concurrency Advanced

Scoped values

Java 8
static final ThreadLocal<User> CURRENT =
    new ThreadLocal<>();
void handle(Request req) {
    CURRENT.set(authenticate(req));
    try { process(); }
    finally { CURRENT.remove(); }
}
Java 25
static final ScopedValue<User> CURRENT =
    ScopedValue.newInstance();
void handle(Request req) {
    ScopedValue.where(CURRENT,
        authenticate(req)
    ).run(this::process);
}
Hover to see modern ➜
JDK 25+ β†’
Concurrency Intermediate

CompletableFuture chaining

Pre-Java 8
Future<String> future =
    executor.submit(this::fetchData);
String data = future.get(); // blocks
String result = transform(data);
Java 8+
CompletableFuture.supplyAsync(
    this::fetchData
)
.thenApply(this::transform)
.thenAccept(IO::println);
Hover to see modern ➜
JDK 8+ β†’
You are visitor 01402503 β€” GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800Γ—600. No cookies required.