0

0

Java中的虚拟线程与传统操作系统线程的区别_载体线程调度与避免上下文切换的阻塞处理

P粉602998670

P粉602998670

发布时间:2026-03-13 10:12:11

|

903人浏览过

|

来源于php中文网

原创

虚拟线程是JVM用户态协程,不注册到OS内核,由ForkJoinPool调度,一个OS线程可承载成千上万个;阻塞操作需JVM识别挂起,否则卡住载体线程。

java中的虚拟线程与传统操作系统线程的区别_载体线程调度与避免上下文切换的阻塞处理

虚拟线程不是“轻量级 OS 线程”

Java 虚拟线程(VirtualThread)根本不在操作系统内核里注册,它只是 JVM 用户态调度的协程。OS 线程(Thread)每个都对应一个 pthread 或 Windows 线程,要进内核排队、占栈、参与 CPU 时间片竞争;而虚拟线程由 JVM 的 ForkJoinPool(默认 carrier pool)在用户态批量调度,一个 OS 线程可承载成千上万个虚拟线程。

常见错误现象:Thread.currentThread().getName() 返回类似 VirtualThread[#123]/runnable,但你以为它能直接调用 Thread.sleep(1000) 就阻塞自己?错——它会把整个载体线程卡住,导致其他虚拟线程饿死。

  • 真正阻塞操作(如 Object.wait()Thread.sleep()LockSupport.park())必须由 JVM 识别并挂起虚拟线程,同时释放载体线程去跑别的任务
  • 只有 JDK 内置 I/O(如 Files.readAllBytes()ServerSocket.accept())和明确标注 @Blocking 的 API 才支持自动挂起;自定义 native 调用或 JNI 不触发挂起
  • Thread.ofVirtual().unstarted(Runnable) 启动的才是虚拟线程;直接 new Thread(Runnable) 还是传统线程

载体线程被阻塞时会发生什么

虚拟线程依赖“载体线程”(carrier thread)执行实际 CPU 工作,但载体线程本身是普通 OS 线程。一旦你在虚拟线程里调用了未被 JVM 拦截的阻塞调用(比如老式 InputStream.read() 同步阻塞、或 System.in.read()),JVM 无法感知,只能让该载体线程原地等待,直到阻塞结束。

使用场景:HTTP 客户端用 HttpClient(JDK 11+)没问题,它内部已适配虚拟线程;但若用 Apache HttpClient 4.x 或 OkHttp 3.x,默认仍是阻塞 I/O,会拖垮载体线程池。

立即学习Java免费学习笔记(深入)”;

IngestAI
IngestAI

帮助人们将知识库转变为聊天机器人助手

下载
  • 错误示例:new BufferedReader(new InputStreamReader(System.in)).readLine() —— 在虚拟线程中执行会导致载体线程永久挂起
  • 正确做法:改用 AsynchronousFileChannelHttpClient.newHttpClient(),或显式用 Executors.newCachedThreadPool() 把阻塞操作扔给传统线程池
  • 可通过 JVM 参数 -Djdk.virtualThreadCarrierThreadKeepAliveMillis=1000 控制空闲载体线程存活时间,避免资源滞留

上下文切换开销真的消失了吗

虚拟线程确实消除了 OS 级上下文切换(从用户态到内核态再切回来),但没消灭“调度决策”和“栈保存/恢复”的成本。JVM 仍需在虚拟线程间切换执行权,只是换成了用户态跳转,且栈是堆上分配的 Continuation 对象,不是固定大小的内核栈。

性能影响:创建百万级虚拟线程几乎无压力(Thread.start() 耗时 ~100ns),但频繁在大量虚拟线程间轮转(如每毫秒唤醒一个)会加重 JVM 调度器负担,反而不如固定几个 OS 线程 + 异步回调模型。

  • 别盲目替换所有 ExecutorService:高吞吐、低延迟、计算密集型任务仍适合传统线程池 + ForkJoinPool
  • 虚拟线程最适合 I/O 密集、请求-响应生命周期短、并发连接数高的场景(如 WebFlux 替代方案、gRPC 服务端)
  • 监控关键指标:用 jcmd <pid> VM.native_memory summary 查看 Internal 内存增长;用 jstack -l <pid> 观察虚拟线程状态是否大量卡在 WAITING (parking) 而非 RUNNABLE

为什么 ThreadLocal 在虚拟线程里默认不继承

传统 ThreadLocal 绑定的是 OS 线程实例,而虚拟线程每次可能被不同载体线程执行,所以默认不会跨虚拟线程传递值。这不是 bug,是设计选择:避免隐式状态污染和内存泄漏。

容易踩的坑:Spring 的 RequestContextHolder、Logback 的 MDC 都依赖 ThreadLocal,直接在虚拟线程中用会丢失上下文。

  • 解决方案一:用 InheritableThreadLocal + Thread.Builder.inheritInheritableThreadLocals(true) 显式开启继承(仅限 JDK 21+)
  • 解决方案二:手动在虚拟线程启动前 copy 关键 ThreadLocal 值,例如 MDC.getCopyOfContextMap() + MDC.setContextMap(...)
  • 注意:ThreadLocalremove() 必须显式调用,否则虚拟线程退出后其持有的对象可能长期滞留在载体线程的 ThreadLocalMap
虚拟线程不是银弹,它把“如何高效调度大量阻塞任务”的责任从应用层移交给了 JVM,但前提是你的阻塞点得是 JVM 认得出来的。写个 while(true) { Thread.sleep(1); } 在虚拟线程里,照样卡死整个载体池。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

160

2025.08.06

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

88

2026.01.26

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

107

2023.09.25

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

443

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

605

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

443

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

605

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

443

2023.07.18

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

37

2026.03.12

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.3万人学习

C# 教程
C# 教程

共94课时 | 11.2万人学习

Java 教程
Java 教程

共578课时 | 81万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号