02-虚拟线程与并发编程

知识库
知识库文档
/tech-stacks/java/tutorial/02-虚拟线程与并发编程.md

文档

Java 进阶篇:虚拟线程与并发编程

背景

JDK 21 引入了虚拟线程(Virtual Threads,Project Loom),彻底改变了 Java 的并发模型。与传统平台线程不同,虚拟线程由 JVM 管理,轻量到可以创建百万个。

核心概念

1. 虚拟线程 vs 平台线程

// 传统平台线程 — 重量级(约 1MB 栈内存/线程)
Thread.ofPlatform().start(() -> {
    System.out.println("Platform thread: " + Thread.currentThread());
});

// 虚拟线程 — 轻量级(可创建百万个)
Thread.ofVirtual().start(() -> {
    System.out.println("Virtual thread: " + Thread.currentThread());
});

2. 使用 ExecutorService

// 为每个任务创建一个虚拟线程
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    var futures = IntStream.range(0, 1000)
        .mapToObj(i -> executor.submit(() -> {
            Thread.sleep(Duration.ofMillis(100)); // 虚拟线程不阻塞
            return "Task " + i + " done";
        }))
        .toList();

    futures.forEach(f -> {
        try { System.out.println(f.get()); }
        catch (Exception e) { e.printStackTrace(); }
    });
}
// 1000 个虚拟线程,0.1 秒全部完成!

3. Spring Boot 集成虚拟线程

# application.properties
spring.threads.virtual.enabled=true  # Spring Boot 3.2+
@Bean
public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
    return protocolHandler -> protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
}

4. CompletableFuture 进阶

// 组合多个异步调用
CompletableFuture<String> userFuture = 
    CompletableFuture.supplyAsync(() -> fetchUser(id), virtualExecutor);
CompletableFuture<Integer> orderFuture = 
    CompletableFuture.supplyAsync(() -> fetchOrders(id), virtualExecutor);

String result = CompletableFuture
    .allOf(userFuture, orderFuture)
    .thenApply(v -> String.format(
        "用户: %s, 订单数: %d",
        userFuture.join(), orderFuture.join()
    ))
    .exceptionally(ex -> "Error: " + ex.getMessage())
    .join();

5. 线程安全的集合

// ❌ 线程不安全
Map<String, Integer> map = new HashMap<>();

// ✅ ConcurrentHashMap
Map<String, Integer> safeMap = new ConcurrentHashMap<>();

// ✅ CopyOnWriteArrayList — 读多写少场景
List<String> list = new CopyOnWriteArrayList<>();

// ✅ ConcurrentLinkedQueue — 高并发队列
Queue<String> queue = new ConcurrentLinkedQueue<>();

虚拟线程最佳实践

场景 建议
I/O 密集型(HTTP/DB 调用) 虚拟线程极佳
CPU 密集型 用平台线程 + ForkJoinPool
使用 synchronized 会 pin 住虚拟线程,优先用 ReentrantLock
ThreadLocal 避免大量使用,改用 ScopedValue(JDK 21 preview)
连接池 虚拟线程减少连接池压力,但数据库连接池仍需限制

思考题

  1. 虚拟线程为什么不适合 CPU 密集型任务?在什么条件下会 pin 住底层平台线程?
  2. ReentrantLocksynchronized 在虚拟线程下的行为有什么区别?
  3. 如果数据库连接池只有 10 个连接,启动 10000 个虚拟线程同时查询会怎样?

信息

路径
/tech-stacks/java/tutorial/02-虚拟线程与并发编程.md
更新时间
2026/5/30