首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Java 21 虚拟线程与结构化并发:从线程模型到工程化落地

Java 21 虚拟线程与结构化并发:从线程模型到工程化落地

原创
作者头像
资源大佬 jzit-top
发布于 2026-10-15 16:11:41
发布于 2026-10-15 16:11:41
310
举报

Java 的线程模型一直是高并发系统的核心。传统平台线程(Platform Thread)与操作系统线程 1:1 映射,创建成本高、内存占用大,导致开发者不得不依赖线程池、异步回调和响应式编程来提升吞吐。但这也带来了回调地狱、上下文丢失、调试困难等问题。

Java 21 正式引入虚拟线程(Virtual Thread),并预览结构化并发(Structured Concurrency),目标很明确:让开发者用同步阻塞的写法,获得高并发的吞吐。

一、虚拟线程:轻量级线程

虚拟线程由 JVM 调度,多个虚拟线程映射到少量平台线程上,属于 M:N 模型。它适合 IO 密集型任务,比如 HTTP 调用、数据库查询、文件读写。

创建虚拟线程:

代码语言:javascript
复制
Thread vThread = Thread.ofVirtual()
        .name("v-thread-", 0)
        .start(() -> {
            System.out.println("Running in virtual thread: " + Thread.currentThread());
        });
vThread.join();

更常用的方式是使用每任务一个虚拟线程的执行器:

代码语言:javascript
复制
import java.time.Duration;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;

public class VirtualThreadDemo {
    public static void main(String[] args) {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            IntStream.range(0, 10_000).forEach(i -> executor.submit(() -> {
                Thread.sleep(Duration.ofSeconds(1));
                return i;
            }));
        } // 自动 close,等待任务结束
    }
}

这段代码创建 1 万个虚拟线程,每个睡 1 秒。传统平台线程下,这可能需要大量内存和线程池调优;虚拟线程则可以轻松承载。

二、适用场景与边界

虚拟线程不是银弹:

  • 适合:IO 密集、阻塞式调用、高并发请求;
  • 不适合:CPU 密集计算,虚拟线程不会提升算力;
  • 不要池化:虚拟线程很轻,池化反而增加复杂度;
  • 慎用 ThreadLocal:大量虚拟线程可能放大 ThreadLocal 内存占用;
  • 限流:下游资源有限时,用 Semaphore 控制并发。
代码语言:javascript
复制
import java.util.concurrent.Semaphore;

public class RateLimitedService {
    private final Semaphore semaphore = new Semaphore(100);

    public String call() throws InterruptedException {
        semaphore.acquire();
        try {
            return remoteCall();
        } finally {
            semaphore.release();
        }
    }

    private String remoteCall() throws InterruptedException {
        Thread.sleep(200);
        return "ok";
    }
}

三、结构化并发:让并发任务有边界

结构化并发把一组相关任务视为一个工作单元:要么全部成功,要么一起失败,避免线程泄漏和任务失控。Java 21 中 StructuredTaskScope 是预览 API,需要 --enable-preview。

代码语言:javascript
复制
import java.util.concurrent.StructuredTaskScope;
import java.util.function.Supplier;

public class UserService {

    public Response load() throws Exception {
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
            Supplier<String> user = scope.fork(this::fetchUser);
            Supplier<String> order = scope.fork(this::fetchOrder);

            scope.join();           // 等待所有子任务
            scope.throwIfFailed();  // 任一失败则抛出

            return new Response(user.get(), order.get());
        }
    }

    private String fetchUser() throws InterruptedException {
        Thread.sleep(100);
        return "user";
    }

    private String fetchOrder() throws InterruptedException {
        Thread.sleep(150);
        return "order";
    }

    public record Response(String user, String order) {}
}

ShutdownOnFailure 会在任一子任务失败时取消其他任务,避免资源浪费。还有 ShutdownOnSuccess,适合“最快成功即可”的场景。

四、工程实践建议

  1. JDK 选 21+:虚拟线程是正式特性,结构化并发仍需预览;
  2. 框架支持:Spring Boot 3.2+ 可通过 spring.threads.virtual.enabled=true 启用虚拟线程;
  3. 监控:用 JFR 观察虚拟线程数量、阻塞和固定(pinning)情况;
  4. 避免 synchronized 长阻塞:可能固定载体线程,改用 ReentrantLock;
  5. 压测:虚拟线程提升吞吐,但不等于降低延迟,需结合下游容量评估。

五、总结

虚拟线程让 Java 高并发回归简单:用同步代码写异步吞吐。结构化并发则让并发任务具备生命周期和失败传播,减少线程泄漏。两者结合,是 Java 21 之后服务端开发的重要方向。但工程落地仍需关注限流、监控、下游容量和框架兼容性。工具越强,边界越要清晰。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、虚拟线程:轻量级线程
  • 二、适用场景与边界
  • 三、结构化并发:让并发任务有边界
  • 四、工程实践建议
  • 五、总结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档