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

news/2024/7/8 4:17:03 标签: Semaphore, springboot, 线程池

前段时间在群里面发现有个群友抛出一个实际需求:需要通过一个接口拉取数据,这个接口有每秒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.niftyadmin.cn/n/5023919.html

相关文章

Oracle for Windows安装和配置——2.1.Oracle for Windows安装

​2.1.1. 准备Oracle软件 1&#xff09;下载或拷贝安装软件 下载地址:otn.oracle.com或my oracle support。下载文件列表。具体如图2.1.1-1所示。 图2.1.1-1 下载文件列表 --说明&#xff1a; 1&#xff09;通过otn.oracle.com站点&#xff0c;可以免费下载用于安装的Oracle…

jmeter线程组 bzm - Concurrency Thread Group 阶梯式压测

简介 bzm - Concurrency Thread Group 不是JMeter的官方插件&#xff0c;而是一种由Blazemeter提供的高级线程组插件&#xff0c;它提供了更灵活的并发性能测试设置。它可以在不同的时间内并发执行不同数量的线程&#xff0c;模拟不同的负载场景。 插件下载地址&#xff08;jme…

浅谈C++|STL初识篇

一.STL的诞生 长久以来&#xff0c;软件界一直希望建立一种可重复利用的东西。 .C的面向对象和泛型编程思想&#xff0c;目的就是复用性的提升 大多情况下&#xff0c;数据结构和算法都未能有一套标准,导致被迫从事大量重复工作 为了建立数据结构和算法的一套标准&#xff0c;诞…

python 自(1)定义变量 数据类型 判断数据类型 转换数据类型 算数运算符 复合运算符 比较运算符 逻辑运算符 赋值运算符

注释 # 注释 就是一个 # 也可以 ctrl / 也可以出来注释 命名规范 # 标识符 由字母 下划线 数字 组成 数字不能开头 # 不可以使用 关键字 # 严格区分大小写 定义变量 # 变量定义 重复利用 # 例如 cons 你好小周 print(cons) print(cons)print("你好小周") #这…

红包森林模式:白酒企业家的新机遇

白酒是中国传统的酒类&#xff0c;也是中国人喜爱的消费品之一。白酒的品牌众多&#xff0c;竞争激烈&#xff0c;如何在市场中脱颖而出&#xff0c;吸引更多的消费者&#xff0c;是每个白酒企业家都关心的问题。今天&#xff0c;我要向大家介绍一种新颖的电商返利模式&#xf…

IO day7

1->x.mind 2-> A进程 B进程

【计算机网络】传输层协议——TCP(上)

文章目录 TCPTCP协议段格式报头和有效载荷如何分离&#xff1f;4位首部长度 TCP可靠性确认应答机制的提出序号和确认序号为什么序号和确认序号在不同的字段&#xff1f; 16位窗口大小 6个标志位标志位本质具体标志位PSHRSTURG 超时重传机制 文章目录 TCPTCP协议段格式报头和有效…

浅谈C++|STL之map篇

一.map 1.1map概念 简介: map中所有元素都是pairpair中第一个元素为key(键值)&#xff0c;起到索引作用&#xff0c;第二个元素为value(实值)所有元素都会根据元素的键值自动排序 本质: . map/multimap属于关联式容器&#xff0c;底层结构是用二叉树实现。 优点: 可以根…