多线程:线程池拒绝策略的四大类型分析
创始人
2025-05-30 14:03:46

在这里插入图片描述

文章目录

  • 一、线程池的拒绝策略
    • 线程池执行原理
  • 二、拒绝策略定义
    • jdk默认提供了四种拒绝策略
      • AbortPolicy(抛出异常,中止任务)
      • DiscardPolicy(直接丢弃,其他啥都没有)
      • DiscardOldestPolicy(丢弃队列最老任务,添加新任务)
      • CallerRunsPolicy
  • 三、案例演示
    • AbortPolicy
    • CallerRunsPolicy
      • DiscardPolicy
      • DiscardOldestPolicy
  • 四、总结

一、线程池的拒绝策略

  • 线程池中,有三个重要的参数,决定影响了拒绝策略:
    • corePoolSize - 核心线程数,也即最小的线程数
    • workQueue - 阻塞队列
    • maximumPoolSize - 最大线程数

线程池执行原理

  1. 当一个线程进来的时候首先会占用 corePoolSize(核心线程数)
  2. 当提交任务数大于 corePoolSize 的时候,会优先将任务放到 workQueue 阻塞队列中,如果超过队列数会扩充线程池中线程数,直到达到 maximumPoolSize 最大线程数配置
  3. 此时,再多余的任务,则会触发线程池的拒绝策略了
  • 总结起来,也就是一句话,当提交的任务数大于(workQueue.size() + maximumPoolSize ),就会触发线程池的拒绝策略

二、拒绝策略定义

  • 拒绝策略提供顶级接口 RejectedExecutionHandler ,其中方法 rejectedExecution 即定制具体的拒绝策略的执行逻辑

jdk默认提供了四种拒绝策略

AbortPolicy(抛出异常,中止任务)

  • 抛出拒绝执行 RejectedExecutionException 异常信息。线程池默认的拒绝策略。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行

DiscardPolicy(直接丢弃,其他啥都没有)

DiscardOldestPolicy(丢弃队列最老任务,添加新任务)

当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入

CallerRunsPolicy

  • 使用调用线程执行任务。当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。但是,由于调用者自己运行任务,如果任务提交速度过快,可能导致程序阻塞,性能效率上必然的损失较大

三、案例演示

AbortPolicy

public static void main(String[] args) throws Exception{//核心线程数int corePoolSize = 5;//最大线程数int maximumPoolSize = 10;//存活时间long keepAliveTime = 5;BlockingQueue workQueue = new LinkedBlockingQueue(10);//测试不同的拒绝策略时,可以调用不同的方法RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, handler);for(int i=0; i<100; i++) {try {executor.execute(new Thread(() -> log.info(Thread.currentThread().getName() + " is running")));} catch (Exception e) {log.error(e.getMessage(),e);}}executor.shutdown();}

解析:executor.execute()提交任务,由于会抛出 RuntimeException,如果没有try.catch处理异常信息的话,会中断调用者的处理流程,后续任务得不到执行(跑不完100个)。可自行测试下,很容易在控制台 console 中能查看到。

CallerRunsPolicy

主体代码同上,更换拒绝策略:

RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();

解析:运行后,在控制台console中能够看到的是,会有一部分的数据打印,显示的是 “main is running”,即使用调用线程处理。

DiscardPolicy

RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();

解析:直接丢弃任务,实际运行中,打印出的信息不会有100条。

DiscardOldestPolicy

RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();

解析:实际运行,打印出的信息也会少于100条。

四、总结

  • 四种拒绝策略是相互独立无关的,选择何种策略去执行,还得结合具体的业务场景。实际工作中,一般直接使用 ExecutorService 的时候,都是使用的默认的 defaultHandler ,也即 AbortPolicy 策略。
  • 个人建议在生产中一般使用:CallerRunsPolicy 这个策略,因为至少他不会丢弃线程,其他三个都是有线程丢失的。当然,还是要结合具体业务去分析,合理使用线程池。
  • 参考博客:
    https://www.cnblogs.com/eric-fang/p/11584142.html
    https://blog.csdn.net/suifeng629/article/details/98884972

相关内容

热门资讯

玩家实测“微乐安徽麻将有没有挂... 您好:微乐安徽麻将这款游戏可以开挂,确实是有挂的,需要软件加微信【8700483】,很多玩家在微乐安...
分享实测“多乐红中麻将到底有挂... 您好:多乐红中麻将这款游戏可以开挂,确实是有挂的,需要软件加微信【69174242】,很多玩家在多乐...
今日重大通报“皇家斗牛到底有没... 您好:皇家斗牛这款游戏可以开挂,确实是有挂的,需要软件加微信【5951795】,很多玩家在皇家斗牛这...
[黑科技分享]“友间十三张为什... [黑科技分享]“友间十三张为什么一直输!”!其实是有挂亲.友间十三张这款游戏是可以开挂的,确实是有挂...
科普实测“乐平正宗麻将可以开挂... 您好:乐平正宗麻将这款游戏可以开挂,确实是有挂的,需要软件加微信【69174242】,很多玩家在乐平...