JDK21-虚拟线程(实战)

背景
系统需要在极短的时间(短时间可以减少实际余额偏差)拉取多个第三方平台的账户余额,并保存到数据库。
每个平台都是HTTP IO 调用 + 数据解析 + DB 写入,典型的IO 密集型任务

一、业务场景简介(将具体的平台脱敏了,是真实数据)

系统涉及多个余额来源:

  • 单账号平台
    • PLATFORM_A
    • PLATFORM_B
    • PLATFORM_C
    • PLATFORM_D
  • 多账号平台(N 个账号,数量不固定)

每次定时任务需要:

  1. 调用平台接口获取余额
  2. 解析返回数据
  3. 保存余额记录到数据库

二、顺序执行版本(传统写法)

核心特点

  • 所有平台按顺序执行
  • 每一个平台的网络 IO 都会阻塞当前线程
  • 总耗时 =所有平台耗时之和
@Slf4j@ComponentpublicclassBalanceTaskSequential{@AutowiredprivateMultiAccountUtilsmultiAccountUtils;@AutowiredprivatePlatformAUtilsplatformAUtils;@AutowiredprivatePlatformBUtilsplatformBUtils;@AutowiredprivatePlatformCUtilsplatformCUtils;@AutowiredprivatePlatformDUtilsplatformDUtils;@AutowiredprivateMultiAccountMappermultiAccountMapper;@AutowiredprivateAccountBalanceMapperaccountBalanceMapper;@ResourceprivateStringRedisTemplateredisTemplate;privatestaticfinalintPLATFORM_MULTI=0;privatestaticfinalintPLATFORM_A=1;privatestaticfinalintPLATFORM_B=2;privatestaticfinalintPLATFORM_C=3;privatestaticfinalintPLATFORM_D=4;@Scheduled(cron="0/5 * * * * ?")publicvoidsaveAccountBalanceTask(){longstartTime=System.currentTimeMillis();log.info("开始拉取所有平台余额(顺序)");// --- PLATFORM_A ---try{BigDecimalbalance=platformAUtils.getBalance().getBigDecimal("balance");saveBalance("PLATFORM_A账号",balance,PLATFORM_A,null);}catch(Exceptione){log.error("PLATFORM_A获取余额异常",e);}// --- PLATFORM_B ---try{ResponseDtodto=platformBUtils.getAccountBalance();if(dto.getCode()==1){BigDecimalbalance=newBigDecimal(JSONObject.parseObject(dto.getData()).getString("data"));saveBalance("PLATFORM_B账号",balance,PLATFORM_B,null);}}catch(Exceptione){log.error("PLATFORM_B获取余额异常",e);}// --- PLATFORM_C ---try{Map<String,String>response=platformCUtils.getMerchantBalance();if("0".equals(response.get("code"))){BigDecimalbalance=JSONObject.parseObject(response.get("data")).getBigDecimal("Money");saveBalance("PLATFORM_C账号",balance,PLATFORM_C,null);}}catch(Exceptione){log.error("PLATFORM_C获取余额异常",e);}// --- PLATFORM_MULTI ---List<AccountApiInfo>multiAccounts=multiAccountMapper.findAllActiveAccounts();for(AccountApiInfoaccount:multiAccounts){try{ResponseDtodto=multiAccountUtils.getBalance(account.getApiKey());if(dto.getCode()==1){BigDecimalbalance=newBigDecimal(dto.getData());saveBalance(account.getName(),balance,PLATFORM_MULTI,account.getPhone());}}catch(Exceptione){log.error("PLATFORM_MULTI账号[{}]获取余额异常",account.getName(),e);}}// --- PLATFORM_D ---try{Stringtoken=redisTemplate.opsForValue().get("platform_d_token");Map<String,String>headers=Map.of("Authorization",token);Map<String,String>data=platformDUtils.getBalance(headers);if("0".equals(data.get("code"))){BigDecimalbalance=newBigDecimal(data.get("data"));saveBalance("PLATFORM_D账号",balance,PLATFORM_D,null);}}catch(Exceptione){log.error("PLATFORM_D获取余额异常",e);}longendTime=System.currentTimeMillis();log.info("顺序任务结束,总耗时: {} ms",endTime-startTime);}privatevoidsaveBalance(Stringname,BigDecimalbalance,inttype,Stringphone){AccountBalanceaccountBalance=newAccountBalance(null,name,phone,balance,type,1,null,LocalDateTime.now());accountBalanceMapper.insert(accountBalance);log.info("{}余额保存成功: {}",name,balance);}}

存在的问题

问题说明
⏳ 总耗时长任意一个平台慢,全局都慢
🧵 线程阻塞HTTP IO 占用线程
📈 扩展性差多账号平台账号数越多越慢

顺序执行时间

三、虚拟线程并发版本(JDK 21+)

设计思路

  • 每个平台一个任务
  • 每个账号一个虚拟线程
  • 使用Executors.newVirtualThreadPerTaskExecutor()
  • 使用CountDownLatch等待所有任务完成
@Slf4j@ComponentpublicclassBalanceTaskConcurrent{@AutowiredprivateMultiAccountUtilsmultiAccountUtils;@AutowiredprivatePlatformAUtilsplatformAUtils;@AutowiredprivatePlatformBUtilsplatformBUtils;@AutowiredprivatePlatformCUtilsplatformCUtils;@AutowiredprivatePlatformDUtilsplatformDUtils;@AutowiredprivateMultiAccountMappermultiAccountMapper;@AutowiredprivateAccountBalanceMapperaccountBalanceMapper;@ResourceprivateStringRedisTemplateredisTemplate;privatestaticfinalintPLATFORM_MULTI=0;privatestaticfinalintPLATFORM_A=1;privatestaticfinalintPLATFORM_B=2;privatestaticfinalintPLATFORM_C=3;privatestaticfinalintPLATFORM_D=4;@Scheduled(cron="0/5 * * * * ?")publicvoidsaveAccountBalanceTask(){longstartTime=System.currentTimeMillis();log.info("开始拉取所有平台余额(并发)");List<AccountApiInfo>multiAccounts=multiAccountMapper.findAllActiveAccounts();inttotalTasks=4+multiAccounts.size();CountDownLatchlatch=newCountDownLatch(totalTasks);try(ExecutorServiceexecutor=Executors.newVirtualThreadPerTaskExecutor()){// --- PLATFORM_A ---executor.submit(()->runBalanceTask(()->{BigDecimalbalance=platformAUtils.getBalance().getBigDecimal("balance");saveBalance("PLATFORM_A账号",balance,PLATFORM_A,null);},"PLATFORM_A",latch));// --- PLATFORM_B ---executor.submit(()->runBalanceTask(()->{ResponseDtodto=platformBUtils.getAccountBalance();if(dto.getCode()==1){BigDecimalbalance=newBigDecimal(JSONObject.parseObject(dto.getData()).getString("data"));saveBalance("PLATFORM_B账号",balance,PLATFORM_B,null);}},"PLATFORM_B",latch));// --- PLATFORM_C ---executor.submit(()->runBalanceTask(()->{Map<String,String>response=platformCUtils.getMerchantBalance();if("0".equals(response.get("code"))){BigDecimalbalance=JSONObject.parseObject(response.get("data")).getBigDecimal("Money");saveBalance("PLATFORM_C账号",balance,PLATFORM_C,null);}},"PLATFORM_C",latch));// --- PLATFORM_MULTI ---for(AccountApiInfoaccount:multiAccounts){executor.submit(()->runBalanceTask(()->{ResponseDtodto=multiAccountUtils.getBalance(account.getApiKey());if(dto.getCode()==1){BigDecimalbalance=newBigDecimal(dto.getData());saveBalance(account.getName(),balance,PLATFORM_MULTI,account.getPhone());}},"PLATFORM_MULTI-"+account.getName(),latch));}// --- PLATFORM_D ---executor.submit(()->runBalanceTask(()->{Stringtoken=redisTemplate.opsForValue().get("platform_d_token");Map<String,String>headers=Map.of("Authorization",token);Map<String,String>data=platformDUtils.getBalance(headers);if("0".equals(data.get("code"))){BigDecimalbalance=newBigDecimal(data.get("data"));saveBalance("PLATFORM_D账号",balance,PLATFORM_D,null);}},"PLATFORM_D",latch));latch.await();}catch(Exceptione){log.error("虚拟线程执行异常",e);}finally{longendTime=System.currentTimeMillis();log.info("定时任务结束,总耗时: {} ms",endTime-startTime);}}privatevoidrunBalanceTask(Runnabletask,Stringname,CountDownLatchlatch){try{task.run();}catch(Exceptione){log.error("{}余额获取异常",name,e);}finally{latch.countDown();}}privatevoidsaveBalance(Stringname,BigDecimalbalance,inttype,Stringphone){AccountBalanceaccountBalance=newAccountBalance(null,name,phone,balance,type,1,null,LocalDateTime.now());accountBalanceMapper.insert(accountBalance);log.info("{}余额保存成功: {}",name,balance);}}

并发执行时间

四、虚拟线程到底解决了什么问题?

1️⃣ IO 不再“占用”线程

传统线程模型:

# OS 线程为操作系统真实线程 1 HTTP 请求 = 1 OS 线程阻塞

虚拟线程模型:

# OS 线程为操作系统真实线程 1 HTTP 请求 = 虚拟线程挂起(不占 OS 线程)

➡️CPU 线程被释放出来给其他任务使用


2️⃣ 并发数量不再是问题

模型可承载并发
线程池几百 ~ 几千
虚拟线程几十万级别

对于多账号余额采集

  • 10 个账号?没区别
  • 100 个账号?没区别
  • 1000 个账号?依然可控

3️⃣ 代码仍然是“同步写法”

这是虚拟线程最恐怖的优势

❌ CompletableFuture 地狱
❌ Reactive 风格侵入
❌ 回调嵌套

✅ try / catch
✅ 顺序逻辑
✅ 易读、易调试


4️⃣ 实际耗时对比(真实业务)

假设:

  • 单个平台平均耗时:4个
  • 多账号平台:4 个账号
方案总耗时
顺序执行4430ms
虚拟线程并发1254ms

➡️耗时降低接近 4 倍


五、为什么不直接用线程池?

线程池的根本问题

问题描述
线程昂贵每个线程 1MB+ 栈
易耗尽高并发下 OOM
配置困难core/max/queue 很难调
IO 浪费大量线程在等待

虚拟线程的本质

线程 = 任务抽象,而不是系统资源

JVM 帮你做了:

  • 调度
  • 挂起
  • 恢复
  • 映射到少量载体线程

六、适合使用虚拟线程的场景

✅ HTTP 调用
✅ RPC / 第三方接口
✅ DB 操作
✅ 定时批量任务
✅ 多账号 / 多租户系统

❌ CPU 密集型计算
❌ 高精度实时任务


七、总结

虚拟线程不是“并发新玩法”,而是 Java 并发模型的质变

对这类余额采集系统来说:

  • ✅ 更快
  • ✅ 更稳
  • ✅ 更简单
  • ✅ 更容易扩展

📌一句话结论:

虚拟线程 = 用同步代码写出高并发系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1201008.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【AI黑科技】颠覆传统RAG!PageIndex让AI拥有“推理脑“,金融文档分析准确率98.7%!

相似度 ≠ 相关性&#xff1a;颠覆传统 RAG&#xff0c;PageIndex 让 AI 学会"推理式检索" 在金融文档分析基准 FinanceBench 上达到 98.7% 准确率&#xff0c;超越所有向量检索方案 引言 当你向 AI 提出一个关于 50 页财报的复杂问题时&#xff0c;传统的 RAG&…

大模型Agent Skills配置指南:让AI助手从“智障“变“神助攻“,附销售数据分析实战代码

文章详解大模型Agent Skills配置原则&#xff1a;技能要精准而非空泛、要分层管理而非堆砌、要有逻辑关联而非孤立。通过销售数据分析助手实战案例&#xff0c;展示具体技能和工作流设计方法&#xff0c;提供配置技巧与常见问题解决方案。强调技能配置是持续迭代过程&#xff0…

【学术干货免费领】学术会议海报 | 学术会议必备 | 科研展示 | 科研海报 | 国际学术海报 | 会议参会 | 科研成果展示 | 海报展示 | 90+学术Poster模板0元打包下载,速领!

一句话&#xff1a;只要你的研究需要“被看见”&#xff0c;模板就能让你“被看懂、被记住、被引用”。硕博研究生开题/中期/毕业答辩、学术年会、国内外会议 Poster Session30 min 出图&#xff0c;导师秒过&#xff0c;奖学金加分青年教师/博士后职称评审、基金前期成果墙、校…

震惊!90%的RAG项目都做错了!RAG不是“加模块“,而是构建完整的AI判断体系

RAG不是"加模块"&#xff0c;而是一整套数据与判断体系 提到RAG&#xff08;Retrieval-Augmented Generation&#xff0c;检索增强生成&#xff09;&#xff0c;很多人第一反应可能是&#xff1a;"这不就是给大模型多喂点资料&#xff0c;让它照着说吗&#xf…

【广州南方学院主办 | 斯普林格出版 | 高录用、接收综述文章 | 征稿主题广:人工智能、虚拟现实、艺术、设计类稿件均可接收】第二届人工智能赋能数字创意设计国际学术会议(AIEDCD 2026)

征稿主题广&#xff1a;人工智能、虚拟现实、艺术、设计类稿件均可接收 | 高录用、接收综述文章 第二届人工智能赋能数字创意设计国际学术会议(AIEDCD 2026) The 2nd International Conference on AI - Enabled Digital Creative Design 大会时间&#xff1a;2026年3月27-29…

【大模型实战】Agent开发不再迷茫:从推理到运行,构建能“活下去“的系统

一、什么是一个真正的 Agent 如果对“Agent”缺乏一个在工程上成立的定义&#xff0c;那么后续所有关于模型、框架与实现细节的讨论&#xff0c;都会不可避免地失焦&#xff0c;最终退化为&#xff1a; 模型切换经验SDK 使用说明Demo 级实现技巧 而这些&#xff0c;都无法支…

【AI炸裂】大模型Agent学习指南:131篇顶会论文+321个实战案例+代码,小白也能弯道超车!

当前正是Agent发展的黄金时期&#xff0c;对于想要在该领域发论文的同学来说&#xff0c;掌握其高效的学习路径、深入了解Agent的核心系统形态/技术融合创新至关重要。 本文根据以上三维视角&#xff0c;整理了131篇前沿论文&#xff0c;包含当前顶会热点“多智能体”、“大模…

【大数据毕设全套源码+文档】基于Hadoop和Hive的济南旅游景区数据的分析与可视化的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

移动端测试如何学,超详细的APP测试攻略送上

前言 随着手机应用市场发展的逐渐成熟&#xff0c;手机APP已经渗透到人们的吃穿住行生活&#xff0c;比如手机支付APP、通讯APP、各大应用软件等&#xff0c;关于手机APP安全性能的重要性不言而喻。 鉴于此&#xff0c;做好手机APP测试对于软件开发方把控产品质量有着重要意义…

【AI革命】马斯克X算法大揭秘:人工规则已死,RAG接管一切!程序员必学的顶级架构!

就在最近&#xff0c;马斯克的 xAI 团队更新了 x-algorithm 仓库。这份代码宣告了一个时代的终结&#xff1a;人工规则已死&#xff0c;AI 接管一切。 通过对核心组件 Phoenix 的源码拆解&#xff0c;我发现了一个令人震惊的技术真相&#xff1a;驱动 X 全球亿万流量的底层逻辑…

【大数据毕设源码分享】django基于大数据的共享单车数据分析与可视化的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

AI Agent‘翻车‘别慌!Skills来救场,小白也能当大神!

最近一段时间&#xff0c;如果你关注 Agent 相关的产品和讨论&#xff0c;大概率会注意到一个变化&#xff1a;多款主流工具/平台都相继发布了对 Skills 的支持。 比如&#xff1a;Cursor 的 beta 版里已经开始支持 Skills&#xff0c;Coze 这两天也刚发布了对 Skills 的支持&…

TGF-β 信号通路核心干货解析

TGF-β 信号通路是进化上保守的分泌型多肽介导的信号转导系统&#xff0c;核心参与早期胚胎发育、组织器官形成、免疫监督、组织修复及成体稳态维持&#xff0c;其异常激活或抑制与多种疾病密切相关&#xff0c;是发育生物学、肿瘤学、免疫学分领域的重点研究方向。 一、TGF-β…

【保姆级教程】AI Agent编排新姿势:TurnToken机制让大模型协作像搭积木一样简单!

如何编排 AI Agent&#xff1f; 一句话简介 本文将探讨如何将 AIAgent 作为一等公民集成到工作流中&#xff0c;利用 TurnToken 机制触发智能体协作&#xff0c;构建复杂的 AI 业务流程。 &#x1f914; Executor vs Agent 在 MAF Workflow 中&#xff0c;我们有两种主要的执…

【大数据毕设源码分享】springboot基于Hadoop和Hive的济南旅游景区数据的分析与可视化的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

腾讯技术面:数据库核心八股终极典藏版

1.背景国内云厂商从2010年左右正式推出云服务开始&#xff0c;关系数据库作为核心产品&#xff0c;18年以前聚焦于传统关系型数据库如何更好的上云托管&#xff0c;提供开箱即用&#xff0c;以及企业级的高性能、高可靠、高稳定的能力。随着泛互联网的持续发展&#xff0c;云计…

多模态RAG真香!一文带你掌握AI开发的最新技术趋势,小白也能秒懂的编程干货!

“ 多模态RAG目前主流的思路有两种&#xff0c;一种是模态对齐&#xff0c;另一种是使用文本作为中间模态进行转换。” RAG技术目前已经被广泛应用于智能问答&#xff0c;知识库等场景&#xff1b;但随着需求的不断深化&#xff0c;简单的文本问答已经很难满足需求&#xff0c…

【大数据毕设全套源码+文档】基于Django的IT行业招聘数据分析与岗位推荐系统设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

【大数据毕设源码分享】基于django的IT行业招聘数据分析与岗位推荐系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

「干货合集」NF-κB 信号通路:核心机制、功能与科研应用全解析

NF-κB 信号通路是哺乳动物体内进化保守的转录因子介导信号系统&#xff0c;核心功能是调控细胞对炎症、感染、应激等外界刺激的响应&#xff0c;参与免疫平衡维持、细胞增殖与存活等关键生理过程&#xff0c;其异常激活与多种疾病密切相关&#xff0c;是炎症生物学、肿瘤学、免…