给用户发消息任务超出队列,用哪个拒绝策略? 有其他方法吗

解决方案:
自定义线程池的拒绝策略将被拒绝的任务投递到MQ队列【线程池与mq简单结合使用】

一、简介

        在我们使用线程池的过程中,经常会遇到超出线程池的缓存队列、超出的最大线程数,这个时候,如果使用的是默认的拒绝策略即直接抛出异常,此时我们的数据就被丢弃了,程序会停止,我们也不知道,因为程序是并发执行的,如果使用了try catch 捕获异常让程序继续执行,但是被拒绝的线程数据已经被丢弃了,今天我们来学习通过自定义线程池的拒绝策略来解决这个问题,可以更加灵活的使用线程池。

报错信息:
 

rejected from java.util.concurrent.ThreadPoolExecutor@41703c85[Running, pool size = 50, active threads = 50, queued tasks = 10000, completed tasks = 909]

在这里插入图片描述 

1.1 线程池的参数解释

corePoolSize:线程池中核心线程数的数量
maximumPoolSize:在线程池中允许存在的最大线程数
keepAliveTime:当存在的线程数大于corePoolSize,那么会找到空闲线程去销毁,此参数是设置空闲多久的线程才被销毁。
unit:时间单位
workQueue:工作队列,线程池中的当前线程数大于核心线程的话,那么接下来的任务会放入到队列中
threadFactory:在创建线程的时候,通过工厂模式来生产线程。这个参数就是设置我们自定义的线程创建工厂。
handler:如果超过了最大线程数,那么就会执行我们设置的拒绝策略


1.2 线程池工作流程

当corePoolSize个任务时,来一个任务就创建一个线程。
如果当前线程池的线程数大于了corePoolSize那么接下来再来的任务就会放入到我们上面设置的workQueue队列中。
如果此时workQueue也满了,那么再来任务时,就会新建临时线程,那么此时如果我们设置了keepAliveTime或者设置了allowCoreThreadTimeOut,那么系统就会进行线程的活性检查,一旦超时便销毁线程。
如果此时线程池中的当前线程达到了maximumPoolSize最大线程数,那么就会执行我们刚才设置的handler拒绝策略。


1.3 线程池的四种拒绝策略

AbortPolicy :默认的拒绝策略,如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常。
DiscardPolicy :如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常。
DiscardOldestPolicy :如果队列满了,会将最早进入队列的任务删掉腾出空间,再尝试加入队列。
CallerRunsPolicy:如果添加到线程池失败,那么主线程会自己去执行该任务,不会等待线程池中的线程去执行。


二、代码实现

2.1 实现Runnable接口

自定义CrmOpneTaskRunable类 实现Runnable接口,并重写run方法。
在这里插入图片描述

2.2 创建线程池

在这里插入图片描述 

    private ThreadPoolExecutor threadPoolExecutor(){
        return  new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                keepAliveSeconds,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(queueCapacity),
                Executors.defaultThreadFactory(),
                //TODO 自定义拒绝策略  RejectedExecutionHandler实现rejectedExecution方法
                (r, executor) -> {
                    if (r instanceof CrmOpneTaskRunable) {
                        CrmOpneTaskRunable crmOpneTaskRunable = (CrmOpneTaskRunable) r;
                        //直接打印
                        log.info("线程池队列已满,超出最大线程数,投递队列处理...");

                        rabbitTemplate.convertAndSend("direct-rejected-policy",crmOpneTaskRunable.getX().toString());
                    }

                }
        );
    }

通过实现RejectedExecutionHandlerrejectedExecution方法来自定义拒绝策略:
在这里插入图片描述

我们可以通过Lambda表达式形式书写。

2.3 使用线程池

使用try catch 包裹一下。
注意:我们在创建Runnable接口的时候使用有参构造将参数传递进去。
因为如果我们在Runnable接口里直接使用@Autowired直接注入restTemplate和crmOrderRepository,在使用时会报空指针异常。
在这里插入图片描述

 try {
    pool.execute(new CrmOpneTaskRunable(x,appId,timestamp,sign,url,restTemplate,crmOrderRepository));
  }catch (Exception e){
    log.error("开通失败:"+e.getMessage());
  }

三、测试

线程池拒绝策略:投递MQ队列:

在这里插入图片描述

在这里插入图片描述 

队列消费:

在这里插入图片描述 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值