当前位置:首页 > 文章列表 > 文章 > java教程 > Java virtual thread 访问连接池时并发上限怎么设

Java virtual thread 访问连接池时并发上限怎么设

来源:17golang原创 2026-09-15 04:08:53 0浏览 收藏

如果一批请求都由 Java virtual thread 承载,数据库并发上限仍然不应按虚拟线程数量设置。更稳妥的做法是:让虚拟线程按任务创建,把连接池的 maximumPoolSize 当作数据库连接的第一道硬边界;只有还要保护其他共享资源,或需要给某类请求单独配额时,再增加 Semaphore

要点速览
  • 虚拟线程解决的是大量阻塞任务的承载成本,不会增加数据库连接数。
  • 连接池满时,超出的任务应在获取连接处等待,并受获取超时约束。
  • 最终数值要结合数据库容量、应用实例数、事务持有连接时间和观测指标压测确认。

先分清虚拟线程上限和连接池上限

最容易混淆的是把“可以创建很多虚拟线程”理解成“数据库也可以同时处理很多请求”。虚拟线程在阻塞 I/O 时可以让出底层载体线程,因此适合一请求一线程的同步写法;但 JDBC 查询仍要等待一个真实的数据库连接。

例如,应用可以用 Executors.newVirtualThreadPerTaskExecutor() 为每个任务创建虚拟线程。这个执行器的任务数不是数据库配额,连接资源仍由 DataSource 和连接池决定。不要再创建一个固定大小的平台线程池,把它误当成虚拟线程限流器。

Java virtual thread、ExecutorService、JDBC Task 与 DataSource、Connection Pool、Database 的任务承载域和数据库资源域关系示意图
图1:Java 虚拟线程与 JDBC 连接池的双域边界示意图,说明任务数量和数据库连接数量是两种不同约束。

用连接池的 maximumPoolSize 作为第一道边界

如果问题只有“数据库连接不能超过多少”,先不要叠加信号量。以 HikariCP 为例,maximumPoolSize 包含空闲和使用中的连接,池达到上限且没有空闲连接时,getConnection() 会等待到 connectionTimeout。这已经是一个资源闸门。

HikariConfig config = new HikariConfig();
config.setJdbcUrl(jdbcUrl);
config.setUsername(username);
config.setPassword(password);
// 这个值是单个应用实例的连接上限,不是虚拟线程数量。
config.setMaximumPoolSize(16);
// 连接池排队过久就失败,避免请求无限等待。
config.setConnectionTimeout(2000);
HikariDataSource dataSource = new HikariDataSource(config);

示例里的 16 只是演示配置,不是通用答案。实际预算至少要拆成:数据库允许给该服务的连接数、应用实例数量、其他服务共享的连接数,以及一个事务同时持有的连接数。多实例部署时,不能每台都照抄同一个池大小后再把总连接数相加。

要控制的对象优先配置判断方式
数据库连接总数maximumPoolSize看数据库连接上限与实例总量
单类请求配额Semaphore看该类请求是否应让出部分连接
最长排队时间connectionTimeout区分连接拿不到与 SQL 执行慢

需要更早限流时再加 Semaphore

当数据库池已经是唯一稀缺资源时,额外的 Semaphore 往往只是制造第二个排队点。它有价值的场景是:报表查询不能占满在线请求的连接,或者一次业务还要同时消耗外部 API 配额、文件句柄等资源。

private final Semaphore reportSlots = new Semaphore(8, true);

public Report loadReport() throws InterruptedException {
    // 只限制报表这类昂贵任务,在线查询仍可使用池中其他连接。
    if (!reportSlots.tryAcquire(1500, TimeUnit.MILLISECONDS)) {
        throw new RejectedExecutionException("报表并发配额已用尽");
    }
    try {
        // 进入许可范围后再借连接,避免拿着连接等待应用配额。
        try (Connection connection = dataSource.getConnection()) {
            return queryReport(connection);
        }
    } finally {
        // 无论查询成功、异常还是中断,都必须归还许可。
        reportSlots.release();
    }
}

这里的 8 应小于或等于你愿意给报表使用的配额,并且要留意“先获取什么、后获取什么”。如果先拿了连接再等信号量,连接会被闲置占用;如果多个资源存在不同获取顺序,还要检查是否可能互相等待。只限制数据库连接时,让连接池自己排队通常更简单。

把连接等待和业务耗时分开观察

调参时不要只盯着虚拟线程数量。至少区分三段时间:等待 Semaphore 的时间、从 getConnection() 开始到拿到连接的时间、真正执行 SQL 的时间。第一段持续变长,说明应用配额可能太小;第二段变长且 active connections 接近池上限,说明池或数据库是瓶颈;第三段变长,则应回到 SQL、锁和数据库负载排查。

HikariCP 的观测项可以帮助确认这个判断:active connectionsidle connectionstotal connectionsthreads awaiting connection 分别说明正在使用、空闲、总量和等待借连接的线程。不要把“等待连接线程多”直接解释成虚拟线程不够。

Java Semaphore、maximumPoolSize、connectionTimeout 与连接池 active、idle、等待线程和数据库执行的静态关系示意图
图2:连接池观测与应用限流的关系示意图,帮助区分 Semaphore 等待、连接池等待和数据库执行时间。

用小步压测确认最终值

先固定查询类型、事务边界和每个应用实例数量,再逐步改变 maximumPoolSize。记录吞吐、P95/P99 延迟、连接获取超时、事务持有时长以及数据库 CPU/锁等待;如果池从 16 调到 32 后吞吐不再提升而等待和数据库负载上升,就没有继续放大的理由。

只有当某个请求类别会挤占其他请求,或者外部资源也有独立配额时,才逐步加入 Semaphore 并比较它的等待时间。最终配置应该表达资源预算,而不是表达虚拟线程的总数。先把连接池作为第一道边界,再用指标决定是否需要第二道边界,通常是最容易解释和回滚的方案。

常见问题

虚拟线程数量是不是应该等于 maximumPoolSize?

不是。虚拟线程可以多于连接池,超出的任务在借连接处等待;两者只有在单任务都必须立即占用一个连接且没有其他等待资源时才会表现出相近的活跃数量。

连接池已经限制连接数,还需要 Semaphore 吗?

只控制数据库连接时通常不需要。若要给报表、批处理或某个租户单独配额,或者还要保护其他资源,才考虑增加独立信号量。

connectionTimeout 越小越好吗?

不一定。它应覆盖正常的短暂排队和网络抖动,同时避免请求无界等待。要结合业务超时、重试策略和数据库执行时间一起设定。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go math/bits.Add64 如何传递进位结果Go math/bits.Add64 如何传递进位结果
上一篇
Go math/bits.Add64 如何传递进位结果
Go 类型别名和定义类型的方法集为什么不同
下一篇
Go 类型别名和定义类型的方法集为什么不同
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    27次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    131次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    65次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    23次使用
  • CMMLU中文大模型评估基准:功能、使用教程与应用场景解析
    CMMLU
    深入了解CMMLU中文评估基准,涵盖67个学科主题,提供数据集下载、Zero-shot/Five-shot评估方法及排行榜,助力优化中文语言模型性能。
    8次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码