【分享】Java线程池的4种拒绝策略

ThreadPoolExecutor线程池组成:

ThreadPoolExecutor构造器
在这里插入图片描述

三大核心参数解释:

  • corePoolSize - 核心线程数
  • maximumPoolSize - 最大线程数
  • keepAliveTime - 空闲线程存活时间

核心线程数通用计算公式:(公式只是合适的理论值,一切以实际为主
1.CPU 密集型的程序 - 核心数 + 1
2. I/O 密集型的程序 - 核心数 * 2)

最大线程数计算公式:核心线程数 * 2


线程池拒绝策略的触发场景

当提交任务数大于 corePoolSize 的时候,会优先将任务放到 workQueue 阻塞队列中。
当阻塞队列饱和后,会扩充线程池中线程数,直到达到 maximumPoolSize 最大线程数配置。
此时,再多余的任务,则会触发线程池的拒绝策略。当提交的任务数大于(workQueue.size() + maximumPoolSize ),就会触发线程池的拒绝策略处理器RejectedExecutionHandler执行对应的处理方法。

在这里插入图片描述


线程池的拒绝策略:

AbortPolicy

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

在这里插入图片描述
测试代码

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class AbortPolicyMain {
    
    

  public static void main(String[] args) {
    
    
    //核心线程数 = 电脑核数 + 1 = 4核 + 1
    int corePoolSize = 5;
    //最大线程数 8
    int maximumPoolSize = 8;
    //空闲线程最大存活时间
    long keepAliveTime = 5;

    BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(10);
    RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
        keepAliveTime, TimeUnit.SECONDS, workQueue, handler);

    int count = 1;
    while (count < 100) {
    
    
      try {
    
    
        int finalCount = count;
        threadPoolExecutor.execute(new Thread(
            () -> System.out
                .println("当前次数: " + finalCount + ",正常运行线程" + Thread.currentThread().getName() + "...")));
      } catch (Exception e) {
    
    
        e.printStackTrace();
      }
      count++;
    }

    //注意:最后关闭线程池
    threadPoolExecutor.shutdown();
  }
}

在这里插入图片描述

CallerRunsPolicy

会使用调用者当前线程执行任务。当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。

在这里插入图片描述
测试代码

扫描二维码关注公众号,回复: 15710557 查看本文章

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CallerRunsPolicyMain {
    
    

  public static void main(String[] args) {
    
    
    //核心线程数 = 电脑核数 + 1 = 4核 + 1
    int corePoolSize = 5;
    //最大线程数 8
    int maximumPoolSize = 8;
    //空闲线程最大存活时间
    long keepAliveTime = 5;

    BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(10);
    RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
        keepAliveTime, TimeUnit.SECONDS, workQueue, handler);

    int count = 1;
    while (count < 100) {
    
    
      try {
    
    
        int finalCount = count;
        threadPoolExecutor.execute(new Thread(
            () -> System.out
                .println("当前次数: " + finalCount + ",正常运行线程" + Thread.currentThread().getName() + "...")));
      } catch (Exception e) {
    
    
        e.printStackTrace();
      }
      count++;
    }

    //注意:最后关闭线程池
    threadPoolExecutor.shutdown();
  }
}

在这里插入图片描述

DiscardPolicy

直接丢弃,啥也不干
在这里插入图片描述

DiscardOldestPolicy

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


总结:

要根据具体的场景需求,采取合适的策略

使用线程池的优点:

  • 降低资源消耗:通过重复利用已创建的线程降低创建/销毁线程的消耗
  • 提高响应速度:当任务来时,不用等线程创建,直接通过线程池已创建的线程直接执行
  • 便于管理:线程池可以统一分配,方便调优和监控线程。

猜你喜欢

转载自blog.csdn.net/weixin_42380504/article/details/126281654