Java 线程池四种拒绝策略

发表于:2022-6-06 09:19

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:小码code    来源:稀土掘金

  四种拒绝策略:
  预先配置
  配置线程池。
  · 核心线程和最大线程都尽量设置的小一点,分别设置成 1 和 2
  小码code阻塞队列设置固定长度的有界队列,长度为 1
  小码code线程工厂设置默认线程工厂
  // 核心线程数
  int corePoolSize = 1;
  // 最大线程数
  int maximumPoolSize = 2;
  // 线程存活时间
  long keepAliveTime = 10;
  // 线程存活时间单位
  TimeUnit unit = TimeUnit.SECONDS;
  // 有界队列 遵循 FIFO 原则
  BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(1);
  // 线程工厂
  ThreadFactory threadFactory = Executors.defaultThreadFactory();

  创建线程任务
  创建线程任务,一个线程任务执行一秒:
  class TaskThread implements Runnable{
                  
   private int i;
   public TaskThread(int i) {
   this.i = i;
   }
   @Override
   public void run() {
   try {
   TimeUnit.SECONDS.sleep(2);
   System.out.println("执行任务:" + i);
   } catch (InterruptedException e) {
   e.printStackTrace();
   }
   }
   }

  拒绝策略一:AbortPolicy
  默认拒绝策略,拒绝任务并抛出任务:
  // 拒绝策略 默认拒绝策略,拒绝任务并抛出异常:
  RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
  ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize,
   maximumPoolSize,
   keepAliveTime,
   unit,
   workQueue,
   threadFactory,
   handler);
   for (int i = 1; i <= 5; i++) {
   try {
   threadPool.execute(new TaskThread(i));
   } catch (Exception e) {
   System.out.println("【任务" + i + "】报错:" + e.getMessage());
   }
   }

  输出:
  【任务】4报错:Task com.test.controller.ThreadPoolController$TaskThread@5c0369c4 rejected from java.util.concurrent.ThreadPoolExecutor@50675690[Running, pool size = 2, active threads = 2, queued tasks = 1, completed tasks = 0]
  【任务】5报错:Task com.test.controller.ThreadPoolController$TaskThread@31b7dea0 rejected from java.util.concurrent.ThreadPoolExecutor@50675690[Running, pool size = 2, active threads = 2, queued tasks = 1, completed tasks = 0]
  执行任务:1
  执行任务:3
  执行任务:2

  最大线程数 + 阻塞队列 = 3,执行到4,5的时候就抛出错误。这里需要用 try catch 捕获异常。任务1、2、3正常执行。
  如果提交的任务都要执行,可以将抛出的错误任务存入在redis中,然后定时从redis中获取任务,再提交执行。
  拒绝策略二:CallerRunsPolicy
  调用线程运行多余的任务。
  更换拒绝策略,将上面的 AbortPolicy 换成 CallerRunsPolicy。
  RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
 
  执行任务,输出:
  执行任务:1
  执行任务:4
  执行任务:3
  执行任务:2
  执行任务:5

  最大线程数 + 阻塞队列 = 3,多余的任务还是继续被执行。
  拒绝策略三:DiscardPolicy
  拒绝任务,不会抛出错误。
  更换策略,将CallerRunsPolicy 换成DiscardPolicy:
  RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
 
  执行任务,输出:
  执行任务:1
  执行任务:3
  执行任务:2

  多余的线程任务提交被拒绝,而只执行最大线程数 + 阻塞队列 数量的任务,并且不会抛出错误。
  拒绝策略四:DiscardOldestPolicy
  只要还有任务新增,一直会丢弃阻塞队列的最老的任务,并将新的任务加入到阻塞队列中。
  更换策略,将DiscardPolicy 换成DiscardOldestPolicy:
  RejectedExecutionHandler handler3 = new ThreadPoolExecutor.DiscardOldestPolicy();
  
  执行任务,输出:
  执行任务:3
  执行任务:1
  执行任务:5

  任务的执行顺序是 核心线程数 —> 阻塞队列 —> 最大线程数,其中任务1,任务3提交成功。
  · 任务2因为在阻塞队列中,
  · 后面的任务4把任务2挤掉,
  · 任务5又把任务4挤掉,所以最后执行的是任务5。
  总结
  本文介绍了线程四种拒绝策略,当工作任务大于最大线程 + 阻塞队列会执行阻塞队列。
  · AbortPolicy 默认策略,拒绝任务,并抛出异常
  · CallerRunsPolicy 调用线程执行对于的任务
  · DiscardPolicy 拒绝任务,不会抛出异常
  · DiscardOldestPolicy 有多余的任务,把阻塞队列最老的任务丢弃,放入新的任务,直到没有新的任务。

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号