java虚拟线程VirtualThreads

一、介绍

2022年9月20号,JDK19引入了虚拟线程,此版本的虚拟线程功能为预览功能。 2023年9月19号jdk21发布,jdk21为LTS长期支持版本。此版本虚拟线程为正式稳定功能。 很多其他语言都支持类似于"虚拟线程"的技术,比如Go、Erlang他们称之为"协程"。不论是虚拟线程还是协程,他们都是轻量级线程其目的都是为了提高并发能力。

线程(Platform Thread)和虚拟线程(Virtual Thread)的区别

线程和底层操作系统的线程是一一对应的,每new Thread()都会在底层操作系统上创建一个线程,平台线程实例本质上是有系统内核的线程调度程序进行调度, 并且线程的总数量受系统线程的总数量限制。 平台线程有以下缺点:

  • 资源有限导致系统线程总量有限,JVM创建的线程数量也会受此限制
  • 平台线程的调度依赖系统的线程调度程序,当平台线程过度线程上下文的切换会消耗大量资源
  • 每个创建一个平台线程都会开辟一块单独的栈控件,消耗内存

以上问题都限制了我们随意创建使用平台线程,为了解决上述问题我们在使用平台线程的时候一般会引入线程池、添加任务队列构建成"生产者消费者"模式,创建好的线程反复利用以此让平台线程适配多变的业务场景。 如果能够这样,我们需要异步操作、提高并发的时候直接new thread去执行,不需要考虑系统性能和消耗等问题那应该会非常便捷。

  • 虚拟线程可以大量创建而不会占用大量内存
  • 由JVM进行调度和切换,不会和系统线程进行绑定
  • 用法和原来的线程差不多、兼容平台现有的api

二、虚拟线程的实现原理

virtual thread = continuation + scheduler

scheduler:

虚拟线程的载体线程,对应JVM的platform thread。如果不指定系统会创建默认的ForkJoinPool来运行。 系统默认的载体线程代码位置: java.lang.VirtualThread#VirtualThread

continuation:

会把需要运行的任务和当前的VirtualThread封装到Continuation中, 当虚拟线程需要阻塞的时候会调用Continuation.yield操作进行阻塞 将Continuation放到载体线程上运行: java.lang.VirtualThread#submitRunContinuation

jdk.internal.vm.Continuation 实现类被封装在 java.base包下,外部的代码不能直接使用。这里修改下idea的编译参数暴露对应的功能。 --add-exports java.base/jdk.internal.vm=ALL-UNNAMED

实验Continuation.yield功能

java 复制代码
@Test
public void t3() {
    ContinuationScope scope = new ContinuationScope("scope");
    Continuation continuation = new Continuation(scope, () -> {
        System.out.println("在yield方法之前运行的代码逻辑");
        Continuation.yield(scope);
        System.out.println("在yield方法之后运行的代码逻辑");
    });
    System.out.println("业务代码调用continuation.run");
    continuation.run();
    System.out.println("已经调用完第一次continuation.run, 开始第二次调用continuation.run");
    continuation.run();
    System.out.println("执行完成");
}

Continuation底层的代码不深入阅读了。只需要记住 Continuation.yield 方法可以使程序代码中断,然后再次调用 Continuation.run 可以从上一次中断的位置继续执行,底层的能力好多是jdk native方法。

三、平台线程和虚拟线程内存占用情况

分别创建10W个平台线程和虚拟线程查看内存占用情况

java 复制代码
/**
 * 虚拟线程和平台线程内存占用情况
 * 运行参数加上 -Xms1024m -Xmx1024m -XX:NativeMemoryTracking=detail
 * jcmd ${pid} VM.native_memory
 */
@Test
public void t5() {
    // 1千虚拟线程、平台线程
    for (long i = 0; i < 1000; i++) {
        // Thread.ofPlatform().start(() -> {
        Thread.ofVirtual().start(() -> {
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
    }
    // 打印pid
    System.out.println(ManagementFactory.getRuntimeMXBean().getName());
    try {
        Thread.sleep(100000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

waylau.com/jep-425-vir... juejin.cn/post/714687... www.cnblogs.com/throwable/p...

相关推荐
咖啡Beans4 分钟前
SseEmitter + WebClient + Flux实现SSE事件流推送
java·spring boot·flux
你三大爷16 分钟前
Safepoint的秘密探寻
java·后端
福大大架构师每日一题31 分钟前
2025-10-02:不同 XOR 三元组的数目Ⅰ。用go语言,给你一个长度为 n 的数组 nums,数组恰好包含 1 到 n 这 n 个整数(每个数出现一次)
后端
努力也学不会java39 分钟前
【Java并发】揭秘Lock体系 -- condition等待通知机制
java·开发语言·人工智能·机器学习·juc·condition
王嘉俊9251 小时前
Django 入门:快速构建 Python Web 应用的强大框架
前端·后端·python·django·web·开发·入门
我需要打球1 小时前
SpringMVC的执行流程
java·servlet
拾忆,想起1 小时前
RabbitMQ死信交换机:消息的“流放之地“
开发语言·网络·分布式·后端·性能优化·rabbitmq
瑞士卷@1 小时前
JDBC进阶之连接池的配置(Druid与HikariCP)
java·开发语言·数据库
IT_陈寒2 小时前
Redis性能翻倍的5个冷门技巧,90%的开发者从不知道第3点!
前端·人工智能·后端
xiaopengbc2 小时前
泛型在Java集合框架中的应用有哪些?
java·开发语言·python