Java Virtual Threads (Project Loom): Concurrency ยุคใหม่

#java13 เม.ย. 2569

Virtual Threads คืออะไร

Virtual Threads (Java 21) เป็น lightweight threads ที่ JVM จัดการเอง ไม่ผูกกับ OS thread ทำให้สร้างได้หลายล้าน thread โดยไม่กิน memory มาก

Platform Thread vs Virtual Thread

Platform Thread:
- ผูกกับ OS thread 1:1
- สร้างได้ไม่กี่พัน
- Memory ~1MB ต่อ thread
- Blocking I/O ทำให้ OS thread ว่าง

Virtual Thread:
- JVM จัดการ M:N mapping
- สร้างได้หลายล้าน
- Memory ~few KB ต่อ thread
- Blocking I/O ไม่ block OS thread

สร้าง Virtual Thread

// สร้าง virtual thread
Thread vt = Thread.ofVirtual().start(() -> {
    System.out.println("Virtual thread: " + Thread.currentThread());
});

// Virtual thread factory
ThreadFactory factory = Thread.ofVirtual().factory();
Thread t = factory.newThread(() -> System.out.println("Hello!"));
t.start();

// ExecutorService กับ virtual threads
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 1_000_000; i++) {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return "done";
        });
    }
}
// สร้าง 1 ล้าน virtual threads ได้สบาย!

ตัวอย่าง Web Server

// Spring Boot 3.2+ - เปิดใช้ virtual threads
@Bean
public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
    return protocolHandler -> {
        protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
    };
}

// หรือใน application.properties
// spring.threads.virtual.enabled=true

Structured Concurrency

import java.util.concurrent.StructuredTaskScope;

try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    Future<User> userFuture = scope.fork(() -> fetchUser(1));
    Future<List<Order>> ordersFuture = scope.fork(() -> fetchOrders(1));

    scope.join();           // รอทั้งคู่
    scope.throwIfFailed();  // throw ถ้ามี error

    User user = userFuture.resultNow();
    List<Order> orders = ordersFuture.resultNow();

    return new UserProfile(user, orders);
}

Performance Comparison

// Platform threads - จำกัดที่ ~10,000
try (ExecutorService exec = Executors.newFixedThreadPool(10_000)) {
    // ...
}

// Virtual threads - ได้ 1,000,000+
try (ExecutorService exec = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 1_000_000; i++) {
        exec.submit(this::doWork);
    }
}

ข้อควรระวัง

// ❌ อย่าใช้ synchronized กับ blocking I/O ใน virtual thread
synchronized (lock) {
    Thread.sleep(1000);  // pin carrier thread!
}

// ✅ ใช้ ReentrantLock แทน
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
    Thread.sleep(1000);  // ไม่ pin carrier thread
} finally {
    lock.unlock();
}

สรุป

Virtual Threads เปลี่ยนวิธีเขียน concurrent Java ไปมาก ทำให้เขียน blocking code ได้โดยไม่เสีย performance เหมาะกับ I/O-intensive applications เช่น web servers, microservices ครับ