Java虚拟线程实战:Project Loom让并发编程更简单

前言

Java 21 正式引入虚拟线程(Virtual Threads),这是 Project Loom 的核心成果。虚拟线程让 Java 并发编程从”难”变”简”,彻底改变了高并发应用的开发方式。本文带你全面掌握虚拟线程。

一、虚拟线程 vs 平台线程

  • 平台线程:对应操作系统线程,创建成本高(约1MB栈内存),数量受限
  • 虚拟线程:JVM 管理的轻量级线程,创建成本极低(约几KB),可创建数百万个
// 平台线程:创建100万个会OOM
Thread platformThread = new Thread(() -> doWork());
platformThread.start();

// 虚拟线程:创建100万个轻松搞定
Thread virtualThread = Thread.ofVirtual().start(() -> doWork());

二、创建虚拟线程的四种方式

// 方式1:Thread.ofVirtual()
Thread vt1 = Thread.ofVirtual().name("vt-1").start(() -> {
    System.out.println("Virtual thread: " + Thread.currentThread());
});

// 方式2:Thread.startVirtualThread()
Thread vt2 = Thread.startVirtualThread(() -> {
    System.out.println("Running in virtual thread");
});

// 方式3:虚拟线程 ExecutorService
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    executor.submit(() -> processRequest());
    executor.submit(() -> processRequest());
}

// 方式4:ThreadFactory
ThreadFactory factory = Thread.ofVirtual().factory();
Thread vt4 = factory.newThread(() -> doWork());
vt4.start();

三、实战:高并发 HTTP 请求处理

// 传统方式:线程池,受限于线程数
ExecutorService threadPool = Executors.newFixedThreadPool(200);

// 虚拟线程方式:每个请求一个虚拟线程
@RestController
public class UserController {

    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        // 虚拟线程会在 I/O 阻塞时自动挂起,释放载体线程
        return userService.findById(id);  // 数据库查询
    }
}

// Spring Boot 3.2+ 开启虚拟线程
// application.yml
// spring:
//   threads:
//     virtual:
//       enabled: true

四、性能对比测试

public class PerformanceTest {

    // 模拟 I/O 密集型任务
    static void ioTask() throws InterruptedException {
        Thread.sleep(100);  // 模拟数据库查询
    }

    public static void main(String[] args) throws Exception {
        int taskCount = 10_000;

        // 平台线程池
        long start1 = System.currentTimeMillis();
        try (ExecutorService pool = Executors.newFixedThreadPool(200)) {
            List<Future<?>> futures = new ArrayList<>();
            for (int i = 0; i < taskCount; i++) {
                futures.add(pool.submit(() -> { ioTask(); return null; }));
            }
            for (Future<?> f : futures) f.get();
        }
        System.out.println("Platform threads: " + (System.currentTimeMillis() - start1) + "ms");
        // 输出约:5200ms

        // 虚拟线程
        long start2 = System.currentTimeMillis();
        try (ExecutorService vExecutor = Executors.newVirtualThreadPerTaskExecutor()) {
            List<Future<?>> futures = new ArrayList<>();
            for (int i = 0; i < taskCount; i++) {
                futures.add(vExecutor.submit(() -> { ioTask(); return null; }));
            }
            for (Future<?> f : futures) f.get();
        }
        System.out.println("Virtual threads: " + (System.currentTimeMillis() - start2) + "ms");
        // 输出约:120ms,提升40倍!
    }
}

五、注意事项

  1. 避免 synchronized 块:会导致虚拟线程固定(pinning),改用 ReentrantLock
  2. 不适合 CPU 密集型任务:虚拟线程优势在 I/O 密集型场景
  3. ThreadLocal 谨慎使用:大量虚拟线程时内存占用可能增加
// 错误:synchronized 导致 pinning
synchronized (lock) {
    Thread.sleep(100);  // 虚拟线程被固定,无法挂起
}

// 正确:使用 ReentrantLock
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
    Thread.sleep(100);  // 虚拟线程可以正常挂起
} finally {
    lock.unlock();
}

总结

虚拟线程是 Java 并发编程的重大突破,特别适合 I/O 密集型的微服务场景。升级到 Java 21 + Spring Boot 3.2,一行配置即可享受虚拟线程带来的性能提升。

觉得有帮助请点赞收藏!有问题欢迎评论区交流

文章摘自:https://www.cnblogs.com/czlws/p/19817808/java-virtual-threads-project-loom-concurrency