0

0

如何在 Java 19 虚拟线程中安全执行 CPU 密集型任务

聖光之護

聖光之護

发布时间:2026-03-15 19:10:20

|

569人浏览过

|

来源于php中文网

原创

java 19 虚拟线程虽极大提升了 i/o 密集型应用的并发吞吐,但其共享有限载体线程(carrier threads)的机制,使得不当的 cpu 密集型操作会阻塞整个虚拟线程调度池;本文详解通过专用线程池隔离 cpu 工作负载的实践方案。

java 19 虚拟线程虽极大提升了 i/o 密集型应用的并发吞吐,但其共享有限载体线程(carrier threads)的机制,使得不当的 cpu 密集型操作会阻塞整个虚拟线程调度池;本文详解通过专用线程池隔离 cpu 工作负载的实践方案。

在基于 Java 19 虚拟线程构建的高并发 Web 应用(如 Jetty + VirtualThreadPerTaskExecutor)中,I/O 密集型逻辑(如数据库查询、HTTP 调用)能天然受益于虚拟线程的轻量级挂起/恢复机制。然而,一旦部分请求路径包含 CPU 密集型计算(例如图像处理、加密解密、复杂规则引擎、JSON 大对象序列化等),问题便随之而来:所有虚拟线程最终调度到同一组有限的 JVM 载体线程(默认为 ForkJoinPool.commonPool() 或自定义 CarrierThreadPool)上运行;当多个虚拟线程同时进入 CPU 密集型代码段,它们将持续占用载体线程,导致其他虚拟线程(包括大量等待 I/O 完成后需继续执行的线程)无法获得调度资源——系统表现为整体卡顿、新请求超时、健康检查失败,即“虚拟线程饥饿”

根本解决思路是:严格分离执行域(execution domain)——让 CPU 密集型任务脱离虚拟线程的调度池,交由独立、可控的平台线程池承载。这并非放弃虚拟线程,而是遵循“各尽其职”的设计原则:虚拟线程负责高并发、高等待、低计算的 I/O 编排;平台线程池(如 ThreadPoolExecutor)专责短时可控、计算密集的同步或异步任务。

✅ 推荐实践:使用专用 ExecutorService 承载 CPU 任务

创建一个固定大小(建议 Runtime.getRuntime().availableProcessors())的 ThreadPoolExecutor,用于执行所有已知的 CPU 密集型逻辑:

// 初始化一次,全局复用(如 Spring Bean 或静态单例)
private static final ExecutorService CPU_BOUND_EXECUTOR = 
    Executors.newFixedThreadPool(
        Runtime.getRuntime().availableProcessors(),
        Thread.ofPlatform() // 明确使用平台线程,避免嵌套虚拟线程
            .name("cpu-worker-", 1)
            .factory()
    );

// 在虚拟线程上下文中调用(例如 Jetty Handler 或 Spring WebMvc Controller)
public void handleRequest(HttpExchange exchange) throws IOException {
    // 此处运行在虚拟线程中(由 Jetty 的 virtual thread executor 提供)
    try {
        // ✅ 安全:提交 CPU 任务到专用线程池,并同步等待结果
        String result = CPU_BOUND_EXECUTOR.submit(() -> {
            return expensiveCpuComputation(); // 如:BigInteger.pow(), Jackson tree traversal, etc.
        }).get(); // 阻塞当前虚拟线程 —— 但不阻塞载体线程!

        sendResponse(exchange, result);
    } catch (ExecutionException | InterruptedException e) {
        Thread.currentThread().interrupt(); // 恢复中断状态
        throw new RuntimeException(e);
    }
}

? 关键原理:.get() 会挂起当前虚拟线程,而非阻塞其底层载体线程。JVM 会自动将该虚拟线程从调度队列中移出,释放载体线程去服务其他虚拟线程;待 CPU_BOUND_EXECUTOR 中的任务完成并设置 Future 结果后,虚拟线程被唤醒并继续执行。整个过程不消耗额外载体线程,彻底规避“N 个 CPU 任务耗尽 N 个载体线程”的死锁风险。

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

⚠️ 注意事项与进阶建议

  • 避免在 CPU_BOUND_EXECUTOR 中执行任何阻塞 I/O:该线程池专为 CPU 工作设计,若混入 FileInputStream.read()、Socket.getInputStream().read() 等阻塞调用,会导致平台线程长期闲置,浪费资源并可能引发线程饥饿。I/O 操作请始终保留在虚拟线程中。

    Fotor
    Fotor

    Fotor 在线照片编辑器

    下载
  • 考虑异步非阻塞调用(可选):若业务允许响应式编程模型,可结合 CompletableFuture 实现完全非阻塞链路:

    CompletableFuture<String> cpuFuture = 
        CompletableFuture.supplyAsync(this::expensiveCpuComputation, CPU_BOUND_EXECUTOR);
    cpuFuture.thenAcceptAsync(result -> sendResponse(exchange, result), 
                             virtualThreadExecutor); // 回切虚拟线程发送响应
  • 监控与调优:为 CPU_BOUND_EXECUTOR 启用 JMX 或 Micrometer 指标(如 activeCount, queueSize, completedTaskCount),观察是否持续满负荷;若频繁排队,说明 CPU 任务过载,需优化算法或扩容(但通常不应超过 availableProcessors())。

  • 警惕“伪 CPU 任务”:某些看似计算密集的操作(如正则匹配超长文本、未配置超时的 ObjectMapper.readValue())实为潜在的 O(n²) 或无限循环风险。务必在专用线程池中执行的同时,添加超时保护:

    CPU_BOUND_EXECUTOR.submit(() -> expensiveCpuComputation())
        .orTimeout(3, TimeUnit.SECONDS) // JDK 21+;JDK 19 可用 CompletableFuture.withTimeout()(需第三方库)
        .get();

综上,虚拟线程不是万能银弹,而是现代 Java 并发生态中的关键一环。与其试图让虚拟线程“硬扛”CPU 工作,不如主动设计分层执行策略:以虚拟线程为“主干神经”,以专用平台线程池为“肌肉组织”,二者协同,方能在混合负载场景下兼顾吞吐、响应性与稳定性。

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

WorkBuddy
WorkBuddy

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

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

457

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

549

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

337

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

83

2025.09.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

786

2023.08.10

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

504

2023.08.14

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

390

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

2112

2023.08.14

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

69

2026.03.13

热门下载

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

精品课程

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

共23课时 | 4.4万人学习

C# 教程
C# 教程

共94课时 | 11.4万人学习

Java 教程
Java 教程

共578课时 | 82.7万人学习

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

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