利用Semaphore实现多线程调用接口A且限制接口A的每秒QPS为10

前段时间在群里面发现有个群友抛出一个实际需求:需要通过一个接口拉取数据,这个接口有每秒10QPS限制,请问如何实现数据拉去效率最大化且限制调用拉取接口每秒10PQPS?我觉得这个需求挺有意思的,跟某群友讨论,发现可以利用JUC包下的Semaphore实现,几行代码就能搞定。这里将实现方案做下整理,算是抛砖引玉吧~

利用Semaphore实现多线程调用接口

  • 一、代码实现
    • 1.自定义线程池ExecutorConfig
    • 2.获取数据接口DataFetchService
    • 3.拉取数据接口核心实现RateLimitedDataFetcher
    • 4.接口实现类DataFetchServiceImpl
    • 5.UserController控制层
  • 二、项目结构及源码下载地址

一、代码实现

1.自定义线程池ExecutorConfig

/*** 线程池配置*/
@Component
public class ExecutorConfig {private static int maxPoolSize = Runtime.getRuntime().availableProcessors();private volatile static ExecutorService executorService;public static ExecutorService getThreadPool() {if (executorService == null){synchronized (ExecutorConfig.class){if (executorService == null){executorService =  newThreadPool();}}}return executorService;}private static ExecutorService newThreadPool(){int queueSize = 1000;int corePool = Math.min(10, maxPoolSize);return new ThreadPoolExecutor(corePool, maxPoolSize, 10000L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>(queueSize),new ThreadPoolExecutor.AbortPolicy());}private ExecutorConfig(){}
}

2.获取数据接口DataFetchService

/*** 获取数据*/
public interface DataFetchService {/*** 获取数据* @return List<User>*/List<User> dataFetchTask();
}

3.拉取数据接口核心实现RateLimitedDataFetcher

@Service
@Slf4j
public class RateLimitedDataFetcher {@Autowiredprivate UserMapper userMapper;private static final int MAX_REQUESTS_PER_SECOND = 10;private Semaphore semaphore = new Semaphore(MAX_REQUESTS_PER_SECOND);private ExecutorService executorService = ExecutorConfig.getThreadPool();public Future<List<User>> fetchData(Integer id) {return executorService.submit((Callable<List<User>>) () -> {try {// 获取许可semaphore.acquire();// 执行网络请求,这里简化为一个延迟操作QueryWrapper qw = new QueryWrapper();//lt是小于,id小于5qw.lt("id", id);return userMapper.selectList(qw);} catch (InterruptedException e) {e.printStackTrace();return null;} finally {// 释放许可semaphore.release();}});}
}

4.接口实现类DataFetchServiceImpl

@Service
@Slf4j
public class DataFetchServiceImpl implements DataFetchService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate RateLimitedDataFetcher rateLimitedDataFetcher;@Overridepublic List<User> dataFetchTask() {List<User> userList = null;try {userList = rateLimitedDataFetcher.fetchData(2).get();} catch (InterruptedException | ExecutionException e) {log.error("DataFetchServiceImpl dataFetchTask error:{}",e.getMessage());}return userList;}
}

5.UserController控制层

/*** 用户控制层** @author hua*/
@RestController
@RequestMapping(value = "/user")
public class UserController {@Autowiredprivate DataFetchService dataFetchService;@GetMapping(value = "/getBatchUser")public ResponseEntity<List<User>> getBatchUser() {List<User> users = dataFetchService.dataFetchTask();HttpStatus status = users == null ? HttpStatus.NOT_FOUND: HttpStatus.OK;return new ResponseEntity<>(users, status);}
}

二、项目结构及源码下载地址

在这里插入图片描述
下载地址 springboot-cacheable 欢迎star哦~

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

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

相关文章

莫比乌斯召回系统介绍

当前召回系统只能召回相关性高的广告&#xff0c;但不能保证该广告变现能力强。莫比乌斯做了如下两点创新&#xff1a; 在召回阶段&#xff0c;引入CPM等业务指标作为召回依据在召回阶段&#xff0c;引入CTR模型&#xff0c;从而召回更多相关性高且变现能力强的广告 参考 百度…

leetcode 26.删除有序数组中的重复项

给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k &#xff0c;你需要做…

mybatis-plus分页

ApiOperation(value "条件过滤分页查询列表")PostMapping("/list/conditions")public ResponseDTO<PageResultDTO<UnitManagementsEntity>> getAllUnitManagementsWithConditions(RequestBody PageParamDTO queryDTO,RequestParam(required …

Python---函数的几种参数

位置参数关键字参数 &#xff08;键值&#xff09;缺省参数 &#xff08;默认值必须写在最后&#xff09;不定长参数 &#xff08;1&#xff1a;位置传递 &#xff0c;2&#xff1a;关键字传递&#xff09;函数作为参数传递 &#xff08;计算逻辑的传递&#xff0c;…

微信小程序如何在切换页面后原页面状态不变

在微信小程序中&#xff0c;如果要实现在切换页面后原页面状态不变&#xff0c;可以通过以下几种方式来实现&#xff1a; 使用全局数据&#xff1a;可以将需要保持状态的数据存储在小程序的全局数据中&#xff0c;这样无论切换到哪个页面&#xff0c;都可以通过全局数据来获取…

5.k8s jenkins集成k8s一键发布案例

文章目录 前言一、jenkins配置1.1 jenkins配置git1.2 jenkins 配置maven1.3 jenkins配置java 二、jenkins流水线配置2.1.新增项目2.2 springboot项目配置git仓库2.3 springboot项目配置maven打包2.4 系统配置 ssh到hadoop1配置&#xff0c;也就是k8s的master节点2.6 springboot…

【多线程】常见的锁策略

常见的锁策略 1. 乐观锁 vs 悲观锁2. 读写锁 vs 普通互斥锁3. 重量级锁 vs 轻量级锁4. 自旋锁&#xff08;Spin Lock&#xff09;vs 挂起等待锁5. 公平锁 vs 非公平锁6. 可重入锁 vs 不可重入锁7. Synchronized8. 相关面试题 1. 乐观锁 vs 悲观锁 悲观锁&#xff1a; 总是假设…

安防监控系统/视频云存储EasyCVR平台视频无法播放是什么原因?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

誉天在线项目~ElementPlus Tag标签用法

效果图 页面展现 <el-form-item label"课程标签"><el-tagv-for"tag in dynamicTags":key"tag"class"mx-1"closable:disable-transitions"false"close"handleClose(tag)"style"margin:5px;">…

Arcgis多值提取至点所有波段数值一样

Arcgis多值提取至点所有波段数值一样 问题描述 进行多值提取多波段后的结果&#xff0c;所有波段数值都是一样的。 原因 操作流程问题&#xff0c;输入栅格只选择了一个栅格文件 解决方案 实际上&#xff0c;每个波段都会对应一个栅格文件&#xff0c;要把这些添加进去 这…

进程地址空间(Linux虚拟内存机制)

文章目录 一.Linux进程地址空间的结构二.Linux管理进程地址空间的方式三.Linux进程使用物理内存的模型四.进程地址空间的存在意义 本章理论基于32位平台的Linux–kernel 2.6.32版本内核 一.Linux进程地址空间的结构 为了保证内存安全,现代操作系统不允许应用程序(进程)直接访问…

(二十八)大数据实战——Flume数据采集之kafka数据生产与消费集成案例

前言 本节内容我们主要介绍一下flume数据采集和kafka消息中间键的整合。通过flume监听nc端口的数据&#xff0c;将数据发送到kafka消息的first主题中&#xff0c;然后在通过flume消费kafka中的主题消息&#xff0c;将消费到的消息打印到控制台上。集成使用flume作为kafka的生产…

从零开发短视频电商 使用Spring WebClient发起远程Http调用

文章目录 依赖使用创建WebClient实例创建带有超时的WebClient实例示例 请求准备获取响应 高级过滤器自定义过滤器 自定义线程池自定义WebClient连接池开启日志错误处理最佳实践 示例异步请求同步请求上传文件重试过滤错误错误处理 参考 Spring WebClient 是 Spring WebFlux 项目…

基于Protege的知识建模实战

一.Protege简介、用途和特点 1.Protege简介 Protege是斯坦福大学医学院生物信息研究中心基于Java开发的本体编辑和本体开发工具&#xff0c;也是基于知识的编辑器&#xff0c;属于开放源代码软件。这个软件主要用于语义网中本体的构建&#xff0c;是语义网中本体构建的核心开发…

高阶导数的概念与公式

目录 高阶导数的概念 常用的高阶导数的公式 隐函数补充 反函数补充 高阶导数的概念 高阶导数是指一阶或二阶及以上的导数。这些导数可以通过连续进行一阶导数的计算来得到。然而&#xff0c;实际计算高阶导数时&#xff0c;存在一些问题&#xff0c;例如对抽象函数高阶导数…

遇见问题:使用mybaties向数据库中插入数据,idea显示插入成功,但是数据库中并没有数据变化?

遇见问题&#xff1a;使用mybaties向数据库中插入数据&#xff0c;idea显示插入成功&#xff0c;但是数据库中并没有数据变化? 可能的原因有几种&#xff1a; 没有提交事务&#xff1a;在使用 MyBatis 进行数据库操作时&#xff0c;需要手动提交事务。你可以在插入数据完成后…

北京映急物流有限公司 面试.net软件工程师岗位

请实现以下算法&#xff0c;语言不限&#xff0c;也可以是伪代码。 1.有一个数组 a[1000]存放了1000整数&#xff0c;这 1000 个数都大于等于 1&#xff0c;小于等于999&#xff0c;并且只有两个数是相同的,剩下的 998 个数均不相同。请写一个最优搜索算法&#xff0c;找出相同…

西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(一)

西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(一) 第一部分:组态配置 具体步骤可参考以下内容: 如下图所示,新建一个项目后,添加一个安全型PLC,这里以1516F-3 PN/DP为例进行说明, 如下图所示,添加CPU完成后,可以看到左侧的项目树中比普通的PLC多了几个选项…

Markdown和PlantUML的基本使用

首先需要在VS Code中安装Markdown extention和plantUML插件 测试标题 这是测试标题&#xff0c;使用一个#号配合标题 测试1级标题 这是1级测试标题&#xff0c;使用2个#号配合标题 测试2级标题 这是2级测试标题&#xff0c;使用3个#号配合标题 这里是多级列表 Part A S…

leetcode 232 用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移除并返回元素int peek() 返回队列开头…