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

news2025/1/18 17:06:13

前段时间在群里面发现有个群友抛出一个实际需求:需要通过一个接口拉取数据,这个接口有每秒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 {
    @Autowired
    private 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小于5
                qw.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 {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RateLimitedDataFetcher rateLimitedDataFetcher;

    @Override
    public 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 {
    @Autowired
    private 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.coloradmin.cn/o/1007901.html

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

相关文章

CopyOnWriteArrayList源码分析

其中唯一的线程安全 List 实现就是 CopyOnWriteArrayList。 特点 由于读取操作不会对原有数据进行修改&#xff0c;因此&#xff0c;对于每次读取都进行加锁其实是一种资源浪费。相比之下&#xff0c;我们应该允许多个线程同时访问 List 的内部数据&#xff0c;毕竟对于读取操…

企业邮箱选择指南:最适合跨境贸易的解决方案推荐

随着全球贸易的不断发展&#xff0c;外贸公司越来越依赖高效的沟通和协作工具。在众多企业邮箱选择中&#xff0c;哪一种最适合外贸公司的需求呢&#xff1f;让我们一起来看看外贸公司常用的企业邮箱解决方案。 对于外贸公司而言&#xff0c;可靠性是选择企业邮箱的首要考虑因…

LC1798. 你能构造出连续值的最大数目(JAVA)

LC1798. 你能构造出连续值的最大数目 题目描述贪心算法代码演示 题目描述 难度 - 中等 Leetcode - 1798. 你能构造出连续值的最大数目 给你一个长度为 n 的整数数组 coins &#xff0c;它代表你拥有的 n 个硬币。第 i 个硬币的值为 coins[i] 。如果你从这些硬币中选出一部分硬币…

前端构建工具 webpack 笔记

1、了解 webpack 1、定义&#xff1a;本质上&#xff0c;webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具&#xff0c;当 webpack 处理应用它会在内部从一个或多个入口点构建一个依赖图(dependency graph)&#xff0c;然后将你项目中所程序时&#xff0c;需的…

YOLO物体检测系列3:YOLOV3改进解读

&#x1f388;&#x1f388;&#x1f388;YOLO 系列教程 总目录 YOLOV1整体解读 YOLOV2整体解读 YOLOV3提出论文&#xff1a;《Yolov3: An incremental improvement》 1、YOLOV3改进 这张图讲道理真的过分了&#xff01;&#xff01;&#xff01;我不是针对谁&#xff0c;在…

《C++ Primer》第3章 字符串、向量和数组(二)

参考资料&#xff1a; 《C Primer》第5版《C Primer 习题集》第5版 3.3 标准库类型vector&#xff08;P86&#xff09; vector 表示对象的序列&#xff0c;其中所有对象的类型相同&#xff0c;每个对象都有一个与之对应的索引。vector 容纳着其他对象&#xff0c;所以常被称…

Linux内核4.14版本——drm框架分析(11)——DRM_IOCTL_MODE_ADDFB2(drm_mode_addfb2)

目录 1. drm_mode_addfb2 2. drm_internal_framebuffer_create 3. drm_fb_cma_create->drm_gem_fb_create->drm_gem_fb_create_with_funcs 4. drm_gem_fb_alloc 4.1 drm_helper_mode_fill_fb_struct 4.2 drm_framebuffer_init 5. 调用流程图 书接上回&#xff0c;使…

springboot对接postgres

安装postgres 注意:下述链接方式会自动创建数据库steven_russell,若需要创建其他数据库&#xff0c;可以手动执行命令创建数据库 docker run --name postgres \ -p 5432:5432 \ -e POSTGRES_USERsteven_russell \ -e POSTGRES_PASSWORD123456 \ -itd --privilegedtrue postgre…

【卖出看涨期权策略(Short Call)】

卖出看涨期权策略&#xff08;Short Call) 卖出看涨期权策略又称为卖出无备兑看涨期权&#xff0c;如果一个投资者在不持有标的资产价格的情况下卖出看涨期权&#xff0c;那么这种策略就是卖出无备兑看涨期权策略。这个策略潜在盈利有限&#xff0c;但是亏损无限。 卖出看涨期…

基于SSM的应急资源管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Git - Git Merge VS Git Rebase

文章目录 概述Flow View小结 概述 Git merge和Git rebase是两种不同的版本控制工作流程&#xff0c;它们用于将一个分支的更改合并到另一个分支。它们有不同的工作原理和应用场景&#xff0c;下面是它们的主要区别&#xff1a; 合并的方式&#xff1a; Git Merge&#xff1a;合…

MySQL间隙锁深入分析

概念 什么是间隙锁&#xff1f; MySQL的间隙锁&#xff08;gap lock&#xff09;是一种锁定相邻数据间隔的机制。 触发时机&#xff1f; 当使用SELECT…FOR UPDATE或UPDATE语句时&#xff0c;MySQL会获取一个范围锁&#xff0c;包括指定条件内的所有数据行&#xff0c;并且还…

离散数学 学习 之 一阶逻辑基本概念 (一 )

个体词可以 理解为主语 &#xff0c; 3 不是偶数 &#xff0c;3 就是 个体常项 凡整数都能被 2 整除 &#xff0c; 整数就是 个体变项 上面的谓词是 &#xff08; 1 &#xff09; 是无理数 &#xff08; 2 &#xff09; 是有理数 &#xff08; 3 &#xff09; 与 同岁 &#xf…

四川百幕晟科技:提升店铺质量方法是什么?

抖店是抖音旗下的移动电子商务平台&#xff0c;为商家提供在线销售和促销的机会。在抖店&#xff0c;经验值是商家评价和信誉的重要指标之一。反映了平台上商户的服务质量和用户满意度。那么&#xff0c;如何查看自己在抖店手机上的体验分数呢&#xff1f; 1、如何查看抖店手机…

C# 随机数生成 Mersenne Twister 马特赛特旋转演算法 梅森旋转算法

NuGet安装MathNet.Numerics 引用: using MathNet.Numerics.Random; /// <summary>/// 包括lower&#xff0c;不包括upper/// </summary>/// <param name"lower"></param>/// <param name"upper"></param>/// <para…

老师如何私发成绩?

尊敬的各位老师&#xff0c;大家好&#xff01;你是否曾经为繁琐的成绩管理和与学生家长的沟通而感到头疼&#xff1f;是否希望有一个简单方便的工具&#xff0c;能够帮助你私发成绩、管理班级和与家长交流&#xff1f;那么&#xff0c;易查分将是你的最佳选择&#xff01;易查…

destoon根据标题删除重复数据

因为采集数据比较庞大&#xff0c;难免出现重复数据&#xff0c;所以写了一个根据标题进行删除重复数据的mysql命令&#xff0c;需要的朋友可以使用。 DELETE from destoon_article_36 where title in (SELECT * from (SELECT title FROM destoon_article_36 GROUP BY title …

想要精通算法和SQL的成长之路 - 受限条件下可到达节点的数目

想要精通算法和SQL的成长之路 - 受限条件下可到达节点的数目 前言一. 相交链表&#xff08;邻接图和DFS&#xff09; 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 相交链表&#xff08;邻接图和DFS&#xff09; 原题链接 public int reachableNodes(int n, int[][] ed…

超强干货,Pytest自动化测试框架fixture固件使用,0-1精通实战

前言 如果有以下场景&#xff1a;用例 1 需要先登录&#xff0c;用例 2 不需要登录&#xff0c;用例 3 需要先登录。很显然无法用 setup 和 teardown 来实现了 fixture 可以让我们自定义测试用例的前置条件 fixture 的优势 命名方式灵活&#xff0c;不局限于 setup 和teard…

黑马JVM总结(七)

&#xff08;1&#xff09;StringTable_编译器优化 “a”“b”对应#4&#xff1a;是去常量池中找ab的这个符号 astore 5&#xff1a;是把这个存入编号为5的局部变量 “ab”对应的指令 #4&#xff0c;跟“a”“b”对应#4下面弄是一样的 在执行s3“ab”这行个代码时&#xf…