当前位置: 首页 > news >正文

Java限流神器:手写一个通用限流任务执行器,支持重试和指数退避!

调用第三方API最怕什么?怕被限流!今天分享一个自制的限流任务执行器,能帮你轻松控制请求频率,还能自动重试失败任务,指数退避不添乱。代码可直接复制到项目中使用~


📌 背景痛点

很多场景下我们需要控制任务的执行速率:

  • 调用淘宝IP接口,对方限制每秒最多1次请求
  • 批量请求第三方API,担心触发限流封禁
  • 任务可能因网络抖动失败,需要自动重试

今天要介绍的RateLimitedExecutor就是为解决这些问题而生的。


🚀 核心功能

限流执行– 每秒最多执行N个任务,超出则排队等待
顺序保证– 任务严格按照提交顺序执行
自动重试– 失败后自动重试(可配置最大次数)
指数退避– 支持退避延迟策略,避免加重服务端压力
异步返回– 使用CompletableFuture获取结果,不阻塞主线程


🧩 类设计(完整代码)

importcom.google.common.util.concurrent.RateLimiter;importjava.util.concurrent.*;importjava.util.function.Function;/** * 限流任务执行器:按固定速率顺序执行任务,支持重试。 * @param <T> 任务返回值类型 */publicclassRateLimitedExecutor<T>{privatefinalBlockingQueue<TaskWrapper<T>>queue=newLinkedBlockingQueue<>();privatefinalRateLimiterrateLimiter;privatefinalintmaxRetries;privatefinallonginitialDelayMs;// 首次重试延迟(毫秒)privatefinaldoublebackoffMultiplier;// 退避乘数(如2.0表示每次翻倍)privatefinalExecutorServiceworker=Executors.newSingleThreadExecutor(r->{Threadt=newThread(r,"RateLimitedExecutor-Worker");t.setDaemon(true);// 设为守护线程,避免阻止JVM退出returnt;});privatevolatilebooleanrunning=true;/** * 构造限流执行器 * @param permitsPerSecond 每秒允许执行的任务数(如1.0表示每秒1次) * @param maxRetries 最大重试次数(不含首次执行) * @param initialDelayMs 首次重试延迟毫秒数 * @param backoffMultiplier 退避乘数(1.0表示固定延迟,>1.0表示指数退避) */publicRateLimitedExecutor(doublepermitsPerSecond,intmaxRetries,longinitialDelayMs,doublebackoffMultiplier){this.rateLimiter=RateLimiter.create(permitsPerSecond);this.maxRetries=maxRetries;this.initialDelayMs=initialDelayMs;this.backoffMultiplier=backoffMultiplier;worker.submit(this::process);}/** * 提交一个任务,返回CompletableFuture异步获取结果 * @param task 需要执行的任务(Callable) * @return 代表异步结果的CompletableFuture */publicCompletableFuture<T>submit(Callable<T>task){CompletableFuture<T>future=newCompletableFuture<>();queue.offer(newTaskWrapper<>(task,future));returnfuture;}// 工作线程主循环privatevoidprocess(){while(running){try{TaskWrapper<T>wrapper=queue.take();// 阻塞直到有任务executeWithRetry(wrapper);}catch(InterruptedExceptione){Thread.currentThread().interrupt();break;}}}// 执行单个任务(带重试)privatevoidexecuteWithRetry(TaskWrapper<T>wrapper){intretries=0;longdelay=initialDelayMs;while(retries<=maxRetries){// 限流:获取令牌,若不足则阻塞rateLimiter.acquire();try{Tresult=wrapper.task.call();wrapper.future.complete(result);return;// 成功,结束}catch(Exceptione){retries++;if(retries>maxRetries){wrapper.future.completeExceptionally(e);return;}// 重试等待(退避)try{Thread.sleep(delay);}catch(InterruptedExceptionie){Thread.currentThread().interrupt();wrapper.future.completeExceptionally(ie);return;}// 更新下次重试延迟delay=(long)(delay*backoffMultiplier);}}}/** * 优雅关闭执行器:等待已提交任务执行完毕,不再接受新任务 */publicvoidshutdown(){running=false;worker.shutdown();// 不再接受新任务try{if(!worker.awaitTermination(5,TimeUnit.SECONDS)){worker.shutdownNow();}}catch(InterruptedExceptione){worker.shutdownNow();Thread.currentThread().interrupt();}}/** * 立即关闭执行器,尝试中断正在执行的任务 */publicvoidshutdownNow(){running=false;worker.shutdownNow();}// 内部任务包装类privatestaticclassTaskWrapper<T>{finalCallable<T>task;finalCompletableFuture<T>future;TaskWrapper(Callable<T>task,CompletableFuture<T>future){this.task=task;this.future=future;}}}

📦 依赖要求

项目需要引入Guava(提供RateLimiter):

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>32.1.2-jre</version></dependency>

⚙️ 构造参数说明

参数类型说明
permitsPerSeconddouble每秒允许执行的任务数。例:1.0→每秒1次,0.5→每2秒1次
maxRetriesint最大重试次数(不含首次执行)。0表示不重试
initialDelayMslong首次重试前的等待时间(毫秒)
backoffMultiplierdouble退避乘数。2.0→每次延迟翻倍;1.0→固定延迟

🛠️ 核心方法

  • CompletableFuture<T> submit(Callable<T> task)
    提交任务,返回CompletableFuture,可异步获取结果或异常。

  • void shutdown()
    优雅关闭:等待已提交任务执行完毕,不再接受新任务。

  • void shutdownNow()
    立即关闭:尝试中断当前执行的任务。


💡 注意事项

  • 执行器内部使用单线程处理任务,严格保证提交顺序
  • 限流基于RateLimiter,每次执行前阻塞直到获取令牌,因此即使任务执行时间极短,也能保证速率限制。
  • 重试期间工作线程会阻塞等待,后续任务不会提前执行,顺序性得以保持。
  • 工作线程默认设为守护线程,当所有用户线程结束时 JVM 会自动退出,无需手动关闭。但建议在应用关闭时调用shutdown()以确保任务完整执行。

🌰 实战示例:调用淘宝IP接口

假设淘宝IP接口地址为http://ip.taobao.com/outGetIpInfo?ip={ip},我们需要:

  • 限制每秒 1 次请求
  • 失败重试 3 次
  • 首次重试延迟 1 秒,指数退避乘数 2.0

Demo 代码

publicclassTaobaoIpDemo{publicstaticvoidmain(String[]args)throwsException{// 创建限流执行器:每秒1次,重试3次,首次延迟1秒,指数退避2.0RateLimitedExecutor<String>executor=newRateLimitedExecutor<>(1.0,// 每秒1次3,// 重试3次1000,// 首次延迟1秒2.0// 指数退避);// 需要查询的IP列表String[]ips={"8.8.8.8","114.114.114.114","223.5.5.5"};// 提交所有任务for(Stringip:ips){CompletableFuture<String>future=executor.submit(()->queryIp(ip));// 异步处理结果future.thenAccept(result->{System.out.println("IP: "+ip+", 结果: "+result);}).exceptionally(ex->{System.err.println("IP: "+ip+", 查询失败: "+ex.getMessage());returnnull;});}// 等待所有任务完成(实际应用中不需要,这里仅演示)Thread.sleep(10000);// 优雅关闭executor.shutdown();}privatestaticStringqueryIp(Stringip){Stringurl="https://ip.taobao.com/outGetIpInfo?accessKey=alibaba-inc&ip="+ip;returnRestClient.create().get().uri(url).retrieve().body(String.class);}}

🎯 适用场景

  • 调用第三方API需要严格限制QPS(如淘宝IP、微信接口、百度地图等)
  • 需要按顺序执行任务(如写入文件、顺序处理消息)
  • 任务可能临时失败,需要自动重试(网络抖动、服务端限流)
  • 希望重试策略为指数退避,避免雪崩效应

📝 总结

这个轻量级的限流任务执行器,代码简洁、功能完整,能帮你轻松解决速率控制 + 顺序执行 + 自动重试三大问题。配合CompletableFuture异步编程,性能与体验兼得。

如果你也在为API限流或任务重试头疼,不妨复制这份代码到项目中试试~


觉得有用?欢迎点赞、在看、转发给更多小伙伴!
也欢迎在评论区交流你的使用心得或改进建议 😊


本文代码已脱敏,可放心复制到生产项目。Guava 版本建议使用 30.0 以上。

📥 源码获取方式

搜索公众号「秋云编程」并关注,回复 demo 即可。**

http://www.jsqmd.com/news/600087/

相关文章:

  • CenterPoint实战:基于热力图的3D目标检测与跟踪全解析
  • macOS下OpenClaw排错指南:Qwen3.5-9B-AWQ-4bit接口连接失败处理
  • 2026年4月汽车维修erp系统品牌推荐指南:汽车维修公司管理系统/汽车维修厂管理系统/汽车维修服务管理系统/选择指南 - 优质品牌商家
  • 2026年知名的深圳仓储货架可靠供应商推荐 - 品牌宣传支持者
  • 从NuttX到OpenVela:小米开源RTOS的跨平台兼容性到底有多强?(ARM/RISC-V实测)
  • 手把手教你用EMQX 5.x和花生壳内网穿透,5分钟搞定个人MQTT调试服务器
  • Codesys 3.5报警功能配置避坑指南:从报警组到确认方式,一次讲透
  • 华为DRS+UGO工具链详解:Oracle迁GaussDB的全自动化实践指南
  • 【fastadmin】自定义批量操作与Excel导入:高效管理多管理员分组策略
  • OpenClaw二次开发:为Qwen3.5-9B增加区域截图分析
  • 5分钟搞定OpenClaw镜像体验:千问3.5-35B-A3B-FP8云端沙盒部署
  • 3分钟搞定WebGL GPU性能测试:手把手教你用Canvas实现动态色彩渲染
  • OpenClaw移动适配:通过飞书远程调用Qwen2.5-VL-7B处理手机截图
  • 你的单波段图不只一种颜色:解锁QGIS隐藏技能,把灰度数据玩出RGB花样
  • 51单片机汇编实战:外部存储器与IO口扩展技术详解
  • arXiv提交前必读:如何选择最适合的许可证与格式要求
  • 从‘Resource temporarily unavailable’聊起:给Linux C/C++新手的EAGAIN避坑指南与心智模型
  • 告别手动操作!手把手教你用影刀RPA+钉钉机器人打造自动化工作流(附完整配置截图)
  • GZCTF动态Flag题目从开发到上架全流程:以Python Flask镜像为例
  • 用MCP协议为你的SpringBoot应用插上AI翅膀:一个学生管理系统的DeepSeek智能查询改造实录
  • seo代理与网站优化公司的区别在哪里
  • OpenClaw压力测试:Kimi-VL-A3B-Thinking在持续调用下的稳定性表现
  • 小白友好!OpenClaw对接Qwen3-4B镜像的3种验证方式
  • 戴尔电脑BIOS设置全攻略:U盘启动Windows系统避坑指南(附闪迪U盘实测)
  • Manim进阶技巧:如何用Python代码制作复杂的数学动画
  • Java版Playwright实战:从零开始搭建自动化测试框架(含完整代码示例)
  • Zemax实战指南:从基础到精通的公差分析技巧
  • 别再死磕PPO了!用DPO微调你的大模型,成本直降80%(附Colab实战代码)
  • OpenClaw配置备份指南:SecGPT-14B模型切换无忧方案
  • MH-Z19 CO₂传感器嵌入式驱动设计与多平台实战