前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >线程池的 RejectedExecutionHandler(拒绝策略)

线程池的 RejectedExecutionHandler(拒绝策略)

作者头像
allsmallpig
发布2021-02-25 15:13:43
1.5K0
发布2021-02-25 15:13:43
举报
文章被收录于专栏:allsmallpi博客

转载自  https://blog.csdn.net/jgteng/article/details/54411423

https://blog.csdn.net/luofenghan/article/details/78596950

JAVA为多线程场景提供了线程池,下面是一个线程池的构造方法:

代码语言:javascript
复制
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }

其中这些参数的使用和说明在我的一篇文章中已经有了介绍,如果不太清楚的可以参考这篇文章:http://blog.csdn.net/jgteng/article/details/54409887 这里想对拒绝策略RejectedExecutionHandler做一下详细的介绍。

在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会有问题,针对这些问题java线程池提供了以下几种策略:

  • AbortPolicy (中止)
  • DiscardPolicy (抛弃)
  • DiscardOldestPolicy  (抛弃最旧) 
  • CallerRunsPolicy (调用者运行)

自定义

AbortPolicy 该策略是线程池的默认策略。使用该策略时,如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常。

  • 该策略是默认的饱和策略;
  • 会抛出未检查的RejectedExecutionException,调用者可以捕获这个异常,然后根据需求编写自己的处理代码;

源码如下:

代码语言:javascript
复制
 public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            //不做任何处理,直接抛出异常
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }

DiscardPolicy 这个策略和AbortPolicy的slient版本,如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常。

  • 当提交的任务无法保存到队列中等待执行时,Discard策略会悄悄抛弃该任务。

源码如下:

代码语言:javascript
复制
   public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            //就是一个空的方法
        }

DiscardOldestPolicy

  • 会抛弃下一个将被执行的任务,然后尝试重新提交的新任务。
  • 如果工作队列是一个优先队列,那么抛弃最旧的策略,会抛弃优先级最高的任务,因此最好不要将抛弃最旧的饱和策略和优先级队列放在一起使用。

源码如下:

代码语言:javascript
复制
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                //移除队头元素
                e.getQueue().poll();
                //再尝试入队
                e.execute(r);
            }
        }

CallerRunsPolicy

  • 该策略既不会抛弃任务,也不会抛出异常,而是当线程池中的所有线程都被占用后,并且工作队列被填满后,下一个任务会在调用execute时在主线程中执行,从而降低新任务的流量。由于执行任务需要一定的时间,因此主线程至少在一定的时间内不能提交任何任务,从而使得工作者线程有时间来处理正在执行的任务。
  • 另一方面,在这期间,主线程不会调用accept,那么到达的请求将被保存在TCP层的队列中而不是在应用程序的队列中。如果持续过载,那么TCP层将最终发现他的请求队列被填满,因此同样会开始抛弃请求。
  • 当服务器过载时,这种过载情况会逐渐向外蔓延开来——从线程池到工作队列到应用程序再到TCP层,最终到达客户端,导致服务器在高负载的情况下实现一种平缓的性能降低。

源码如下: public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {             if (!e.isShutdown()) {                 //直接执行run方法                 r.run();             }         }

自定义 如果以上策略都不符合业务场景,那么可以自己定义一个拒绝策略,只要实现RejectedExecutionHandler接口,并且实现rejectedExecution方法就可以了。具体的逻辑就在rejectedExecution方法里去定义就OK了。 例如:我定义了我的一个拒绝策略,叫做MyRejectPolicy,里面的逻辑就是打印处理被拒绝的任务内容

代码语言:javascript
复制
public class MyRejectPolicy implements RejectedExecutionHandler{
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        //Sender是我的Runnable类,里面有message字段
        if (r instanceof Sender) {
            Sender sender = (Sender) r;
            //直接打印
            System.out.println(sender.getMessage());
        }
    }
}

这几种策略没有好坏之分,只是适用不同场景,具体哪种合适根据具体场景和业务需要选择,如果需要特殊处理就自己定义好了。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/04/24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档