利用线程池来控制访问频率

背景:某资源的查询接口,一共有四个渠道,均要调用查询接口落缓存,且均有QPS限制,现要通过线程池配置来控制查询频率。

渠道A 渠道B 渠道C 渠道D
QPS 5 2 10 2

思路:通过涉及线程池中的核心线程数、最大线程数、队列长度来达到限流的目的,四个渠道因QPS要求不一,则分别配置四个池子。

示例:

@Bean(name = "XxPoolExecutor")
    public ThreadPoolTaskExecutor xxQueryPoolExecutor() {
        String channelPoolSize = annotatedBean.getChannelPoolSize();
        ChannelPoolConfig channelPoolConfig = JSONObject.parseObject(channelPoolSize, ChannelPoolConfig.class);
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(channelPoolConfig.getFlightMasterCorePoolSize());
        executor.setMaxPoolSize(channelPoolConfig.getFlightMasterMaxThreadNum());
        // 线程池维护线程所允许的空闲时间
        executor.setKeepAliveSeconds(60);
        // 队列容量
        executor.setQueueCapacity(1000);
        // 等待任务执行完成在关闭
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
        executor.setAwaitTerminationSeconds(60);
        // 线程前缀名称
        executor.setThreadNamePrefix("async-query-service-");
        // 配置拒绝策略:如果队列满了,继续往队列增加数据,则由调用线程处理该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        try {
            executor.initialize();
        }catch (Exception e){
            e.printStackTrace();
        }
        return executor;
    }

线程池配置有以下几个关键的参数:

更具体的细节及示例见:    手写线程池及四种拒绝策略解析

1.常驻核心线程数

        保证有多少个线程一直在等待新任务的到来,当任务到来时,线程池不用新建线程而是直接利用空闲的核心线程执行任务。

2.队列长度

        当核心线程数打满且有新任务提交时,任务会放在队列等待执行。

3.最大线程数

        线程池能够容纳同时执行的最大线程数,当核心线程及队列都被占满任务时,线程池会判断新提交的任务是否大于最大线程数,若是则触发拒绝策略;反之则新建线程来执行。

        有些晦涩,举例来说:核心线程数为2,队列长度为5,最大线程数为3。

        当第一个,第二个任务被提交到线程池后,可以立即执行;

        若此时前两个任务未执行结束,又过来5个任务,此时队列已满;

        若再提交一个任务,则触发最大线程数(新开一个线程来执行);

        若此时再提交任务,只能触发拒绝策略了。

你可能感兴趣的:(java日常开发总结,java,开发语言)