-
Notifications
You must be signed in to change notification settings - Fork 1
Java Thread vs Virtual Thread
Somkiat Puisungnoen edited this page Jul 15, 2026
·
3 revisions
public class MainThread {
static void main() {
System.out.println("Main thread started: " + Thread.currentThread().getName());
for (int i = 1; i <= 3; i++) {
Thread platformThread = new Thread(() -> {
System.out.println("Platform thread " + Thread.currentThread().getName() + " is running.");
try {
Thread.sleep(2000); // Simulate some work
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Platform thread " + Thread.currentThread().getName() + " finished.");
}, "Platform-Thread-" + i);
platformThread.start();
}
System.out.println("Main thread finished.");
}
}
public class MainVT {
static void main() throws InterruptedException {
System.out.println("Main thread started: " + Thread.currentThread().getName());
for (int i = 1; i <= 100; i++) { // Creating many more threads!
Thread.startVirtualThread(() -> {
System.out.println("Virtual thread " + Thread.currentThread().getName() + "ID=" + Thread.currentThread().threadId() + " is running.");
try {
Thread.sleep(2000); // Simulate blocking I/O
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Virtual thread " + Thread.currentThread().getName() + "ID=" + Thread.currentThread().threadId() + " finished.");
});
}
// Give some time for virtual threads to run
Thread.sleep(3000);
System.out.println("Main thread finished: " + Thread.currentThread().getName());
}
}
public class MainMillionVT {
static void main() throws InterruptedException {
Instant start = Instant.now();
Set<Long> vThreadIds = new HashSet<>();
// Create 1 million virtual threads
var vThreads = IntStream.range(0, 1_000_000).mapToObj(i -> Thread.ofVirtual().unstarted(() -> {
vThreadIds.add(Thread.currentThread().getId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
})).toList();
vThreads.forEach(Thread::start);
for (var thread : vThreads) {
thread.join();
}
Instant end = Instant.now();
System.out.println("Time =" + Duration.between(start, end).toMillis() + " ms");
System.out.println("Number of unique vThreads used " + vThreadIds.size());
}
}
- Deterministic Lifetimes (No Zombie Threads)
- Short-Circuiting Error Handling
- Streamlined Cancellation
- Tree-Like Diagnostic Observability
// Danger: Lacks structural cleanup guarantees
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
Future<String> futureA = executor.submit(() -> fetchDataA());
Future<String> futureB = executor.submit(() -> fetchDataB());
// If futureA.get() throws an exception, futureB keeps running blindly
return futureA.get() + " & " + futureB.get();
}
// Safe: Structured, self-contained unit of work
try (var scope = new StructuredTaskScope<>(SubtaskJoiner.allSuccessful())) {
// Forks subtasks into explicitly tracked virtual threads
Subtask<String> taskA = scope.fork(() -> fetchDataA());
Subtask<String> taskB = scope.fork(() -> fetchDataB());
scope.join(); // Synchronization point: awaits execution or failure
return taskA.get() + " & " + taskB.get();
} // All threads are guaranteed terminated here