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

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

一、代码实现

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哦~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值