登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  java教程

Java 虚拟线程遇到阻塞调用时的线程占用分析

来源:17golang原创

时间:2026-10-17 12:50:19 401浏览 收藏

Java 虚拟线程遇到阻塞调用,不一定持续占用一个平台线程。分析时要分开看虚拟线程是否能够从载体卸载、是否存在固定载体的调用,以及线程等待的数据库连接等资源是否已经耗尽。虚拟线程数量增多,本身不能证明平台线程泄漏,也不能证明吞吐量必然提高。

本文以 JDK 26 文档为主要口径。Java 官方文档入口:https://docs.oracle.com/en/java/javase/26/。下面给出指标记录方法,不报告未执行过的压测成绩。

先记录三个基线,不只看线程总数

面对“并发一高就慢”,先记录固定时间窗口内的完成请求数、延迟分位数与错误率,再记录进程的平台线程、CPU、内存及资源池占用。把请求等待拆成入口排队、资源获取和下游调用,才能知道线程调度是否真是限制。

观察项说明什么不能单独证明什么
虚拟线程及任务积压正在承载或等待的工作规模不能等同于操作系统线程数
载体和平台线程实际线程资源与执行承载不能单凭数量归因于固定载体
连接池获取耗时业务资源竞争不能等同于调度器繁忙
下游响应与超时依赖服务的实际限制不能用更换线程模型消除

基线应带上 JDK 完整版本、处理器配额、堆配置、驱动版本、连接池容量和请求输入。本文没有可报告的基线数值;这些是读者需要在自己环境填写的记录项。

区分阻塞等待与固定载体

JDK 26 文档说明,虚拟线程由运行时安排在载体平台线程上执行,常见阻塞 I/O 可使其卸载,让载体承载其他虚拟线程;文档同时列出 native 方法或 foreign function 场景下的固定限制。不能由“代码使用同步调用风格”直接推出“载体全程被占用”。JDK 26 虚拟线程文档

也要区分版本:JDK 24 已通过相关变更改善 synchronized 构造中的阻塞卸载行为。因此,针对早期 JDK 的“把所有 synchronized 都换掉”不能直接当作 JDK 26 的处理方案。锁竞争导致业务串行,和固定载体,是不同问题。JDK 24 重要变更

虚拟线程与调度器载体和阻塞点的静态依赖图
结构说明图:虚拟线程与载体有关联,但不永久绑定同一载体;可卸载等待与固定限制应按具体调用及 JDK 版本判断。图不是调度时间线。

在真实问题中,可结合线程转储和 JFR 观察具体等待栈、相关事件及持续时间。工具可见范围和事件阈值要按当前 JDK 文档理解,不能仅因未出现某个事件就证明不存在所有类型的线程占用。

连接池满了,轻量等待仍然是等待

假设数据库连接池只有有限连接,虚拟线程可以让更多请求等待获取连接,但不会为数据库增加处理能力。任务即便不长期占用载体,也会持有请求上下文、超时预算和其他内存。无界提交可能把平台线程瓶颈改成更大的等待队列。

因此资源池应单独记录活跃连接、等待数量、获取耗时和获取超时。资源限额应围绕真实下游容量定义;不能因为线程更轻就随意扩大连接池,更不能把虚拟线程池当成数据库容量控制器。

请求任务与连接池和下游容量的静态结构图
资源关系说明图:请求任务需要连接池中的有限资源,调度容量与下游容量不是同一件事;等待规模也会带来内存与超时压力。

一次只改变一个因素,按同口径比较

建议先固定相同输入、相同到达负载、相同预热与统计窗口,比较原有执行方式和虚拟线程方式;保持连接池、下游限制及超时策略不变。不要同时升级驱动、扩大连接池又改变任务模型,再把全部变化归因于虚拟线程。

第二组实验才调整资源并发限制,继续记录完成吞吐、p95/p99、超时率、连接池等待和内存。压测端若只能等待上一请求完成后发送下一请求,也要记录这一限制,避免把客户端供给不足误当服务端已经达到容量上限。

观察到的对比优先解释方向
平台线程压力下降,连接等待仍高线程承载得到改善,业务资源仍受限
任务积压和内存持续上涨检查入口负载与有界并发策略
CPU接近配额且完成量不变检查CPU工作量,不预设I/O调度可解决
少数长调用伴随载体占用检查具体阻塞实现与相关观测证据

这些是判读方向,不是本文测试结果。可靠结论应同时描述负载、资源配置、错误率和延迟,而不只说“线程数少了”。

虚拟线程解决承载方式,不取消容量边界

适合优先评估的是大量等待型任务;长时间 CPU 密集工作不会因为换成虚拟线程而自动加速。保留依赖超时、有界入口及资源释放规则,确认取消是否真正传播到驱动或下游,不能把请求超时等同于资源已经释放。

线程处于等待状态就一定不占载体吗?

不能仅凭状态名推断。需要结合实际调用、JDK版本和运行时证据区分卸载、固定及其他阻塞实现。

连接池等待多,需要增加调度器线程吗?

不应直接这样处理。先确认连接与下游容量限制,否则增加调度承载并不能创造更多可用连接。

虚拟线程很多是否就是异常?

不一定。应结合任务生命周期、积压是否有界、内存和完成请求数判断,而不是使用平台线程时代的数量直觉。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>