怎么利用 Project Loom 的 Continuation 挂起机制理解虚拟线程在阻塞时的状态机转换

秋涛姑娘_5924

秋涛姑娘_5924

2026-04-24

933人浏览

原创

虚拟线程阻塞时由jvm自动挂起并释放载体线程,依赖continuation机制保存/恢复上下文,不暴露api;纯cpu循环不触发挂起,可能导致载体线程饥饿。

怎么利用 project loom 的 continuation 挂起机制理解虚拟线程在阻塞时的状态机转换

虚拟线程在阻塞时不会真“卡住”载体线程,而是靠 JVM 的 Continuation 机制做状态快照和恢复——这不是用户代码能直接调用的 API,但理解它的行为模型,能帮你避开调度陷阱和调试盲区。

Continuation 不是 Kotlin 的 suspend,也不是你能 new 出来的对象

Continuation 在 Project Loom 中是 JVM 内部原语,不暴露为 public API。它不像 Kotlin 协程里那个 Continuation<t></t> 接口,你无法在 Java 代码中声明、实现或手动 resume 它。JVM 在字节码层面自动插入挂起点(比如进入 Thread.sleep()、Object.wait()、文件读写、网络 socket 阻塞等),并在这些点触发 Continuation 的捕获与还原。

常见误解是以为“加了 suspend 就能进虚拟线程”,但 Java 虚拟线程根本不认 suspend 关键字——那是 Kotlin 编译器干的事。Java 侧的挂起完全由 JVM 对阻塞调用的识别驱动。

  • 你写的 Thread.sleep(1000) 在虚拟线程里会触发挂起,但在平台线程里就是真睡 1 秒
  • System.in.read()、Files.readString(path)(未用 NIO)这类同步 I/O 同样会被拦截并挂起虚拟线程
  • 但 while(true) { i++; } 这类纯 CPU 循环不会触发挂起,虚拟线程会一直霸占载体线程,造成饥饿

阻塞时的状态机:RUNNABLE → PARKED → UNPARKED → RUNNABLE

虚拟线程的生命周期状态不是传统 Thread.State 枚举能完整描述的。JVM 内部用更细粒度的状态跟踪 Continuation 行为:

  • 当执行到阻塞点,JVM 把当前栈帧、局部变量、PC 计数器等打包进 Continuation 实例,线程状态对外仍可能是 RUNNABLE(这是故意设计,保持 API 兼容)
  • 底层载体线程被释放,去拉取下一个就绪的虚拟线程任务
  • 阻塞条件满足后(如 sleep 超时、IO 数据到达),JVM 找到对应 Continuation,把上下文恢复到载体线程栈上,继续执行后续字节码

所以你看不到 PARKED 状态出现在 Thread.getState() 返回值里——那是平台线程的状态,不是虚拟线程的。真正反映挂起行为的,是 Thread.currentThread().isVirtual() 为 true,且该线程正在执行阻塞调用。

怎么验证挂起是否生效?别只看线程数,要看载体线程利用率

光看 jstack 或 JFR 里虚拟线程数量暴涨,不能说明挂起机制在工作。关键指标是载体线程(Carrier Thread)是否真的被复用:

  • 启动时加 -XX:+UnlockExperimentalVMOptions -XX:+UseLoom(Java 21+ 默认启用,但显式确认更稳)
  • 用 JFR 录制,筛选事件 jdk.VirtualThreadPinned:出现这个事件,说明某个虚拟线程因执行了禁止挂起的操作(如 native 方法、synchronized 块内阻塞)而“钉住”了载体线程,这是典型调度失效信号
  • 监控 jdk.CarrierThreadStart 和 jdk.CarrierThreadEnd,正常情况下载体线程数应远小于虚拟线程峰值(比如 10 万虚拟线程只启了 200 个载体线程)

如果你发现载体线程数接近虚拟线程数,或者 jdk.VirtualThreadPinned 频繁出现,说明有阻塞操作逃逸了 Continuation 挂起机制——这时候得检查是否用了自定义 native 库、是否在 synchronized 块里做 I/O、或者用了老版本 NIO Channel(未适配 Loom)。

Continuation 的挂起不是魔法,它依赖 JVM 对阻塞点的精确识别和字节码重写。一旦你写的代码绕过了 JVM 的监控路径(比如通过反射调用阻塞方法、或用 Unsafe 操作内存锁),挂起就会失效——这种边界情况很难 debug,但恰恰是线上高并发系统出问题最隐蔽的地方。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

10817

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

7942

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

6892

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1164

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

948

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1416

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

2849

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20131

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1255

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.8万人学习