线程池ThreadPoolExcutor执行流程你弄清楚了么

ThreadPoolExcutor的核心参数

首先来回忆下线程池的几个核心参数;

  1. corePoolSize:核心线程数
  2. maximumPoolSize:最大线程数
  3. keepAliveTime:线程空闲时间
  4. TimeUnit:时间单位
  5. workQueue:线程工作队列
  6. ThreadFactory:线程创建工厂
  7. RejectedExecutionHandler:线程拒绝策略

这些也是我们日常使用线程池,所需要关注的一些参数配置,具体配置的大小,需要根据我们实际服务器的实际情况,这里就做简单了解下,就不过多于纠结了,分为两种情况:

  • IO密集型配置线程数经验值是:2N,其中N代表CPU核数。
  • CPU密集型配置线程数经验值是:N + 1,其中N代表CPU核数。

ThreadPoolExcutor线程池的线程数执行情况

我们通过配置线程池的参数,结合提交的任务数,来去观察任务数、核心线程数、最大线程数和队列之间的变化;

创建线程池

ini 复制代码
public class ThreadPoolTest {
    public static void main(String[] args) {
        //定义一个线程池 核心线程数为4,最大线程数为6,队列长度为2
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
        ThreadPoolExecutor poolExecutor =new ThreadPoolExecutor(4,6,0L, TimeUnit.MILLISECONDS
        ,workQueue);
        // 任务数 3-9
        int work =9;
        for (int i = 1; i <= work; i++) {
            int workCount =i;
            poolExecutor.submit(new Runnable() {
                @Override
                public void run() {
//                    Thread thread =Thread.currentThread();
//                    String threadName =thread.getName();
//                    int activeCount = poolExecutor.getActiveCount();
//                    System.out.println("当前任务:"+workCount+",线程名称"+threadName+",活跃线程数:"+activeCount);
                    System.out.println(Thread.currentThread().getName());
                    try{
                        Thread.sleep(300000L);
                    }catch (InterruptedException ex){
                        ex.printStackTrace();
                    }
                }
            });
            System.out.println("当前任务:"+workCount+",创建第" + i + "个线程后, 线程池情况:" + poolExecutor.toString());
        }     
    }
}

执行结果:

  • 第一种情况:任务数为3,核心线程数为4,最大线程数为6; 任务数<核心线程数; 执行main方法,可以得到活跃的线程数为3个线程
  • 第二种情况:任务数为4,核心线程数为4,最大线程数为6;任务数=核心线程数; 执行main方法,可以得到活跃线程为4;
  • 第三种情况:任务数为5,核心线程数为4,最大线程数为6;任务数>核心线程数,<最大线程数6,会将多出来1个的任务放入在队列等待; 执行main方法,相当于任务数 <核心线程数4+队列长度2, 可以得到活跃线程为4;
  • 第四种情况:任务数为6,核心线程数为4,最大线程数为6;任务数 =核心线程数,=最大线程数6,会将多出来的任务放入在队列等待; 执行main方法,相当于任务数 =核心线程数4+队列长度2, 可以得到活跃线程为4;
  • 第五种情况:任务数为7,核心线程数为4,最大线程数为6;任务数 >核心线程数,>最大线程数6; 执行main方法,相当于任务数 <最大线程数6+队列长度2, 此时任务数为7,线程池会开启4个核心线程执行4个任务,2个任务放入队列等待,此还有一个任务没有执行,但是小于最大线程数6,会再开启一个活跃线程去执行这1一个任务,所以总共活跃线程就是5;
  • 第六种情况:任务数为8,核心线程数为4,最大线程数为6;任务数 =最大核心线程数6+队列2;活跃线程数就是6;
  • 第七种情况:任务数为9,核心线程数为4,最大线程数为6;任务数 >最大核心线程数6+队列2;可以看到在执行到第8个任务的时候,活跃线程数为6,等待队列任务为2,执行到第9个任务的时候,由于任务数 9 >最大核心线程数6+队列2,所以触发了拒绝策略;

总结

在正常情况下,线程池内活跃线程数>核心线程数时,后面进来的任务会加入队列中等待,如果队列已满,会新建线程直到线程池内线程数等于最大线程数,如果还有新的任务进行提交,那么将会触发默认的拒绝策略,AbortPolicy 拒绝创建;

相关推荐
brzhang3 分钟前
代码越写越乱?掌握这 5 种架构模式,小白也能搭出清晰系统!
前端·后端·架构
Asthenia04124 分钟前
为什么MySQL关联查询要“小表驱动大表”?深入解析与模拟面试复盘
后端
南雨北斗7 分钟前
分布式系统中如何保证数据一致性
后端
Asthenia041211 分钟前
Feign结构与请求链路详解及面试重点解析
后端
WuWuII12 分钟前
gateway
java·gateway
左灯右行的爱情14 分钟前
缓存并发更新的挑战
jvm·数据库·redis·后端·缓存
浩宇软件开发18 分钟前
Android开发,实现一个简约又好看的登录页
android·java·android studio·android开发
brzhang18 分钟前
告别『上线裸奔』!一文带你配齐生产级 Web 应用的 10 大核心组件
前端·后端·架构
shepherd11119 分钟前
Kafka生产环境实战经验深度总结,让你少走弯路
后端·面试·kafka
南客先生25 分钟前
多级缓存架构设计与实践经验
java·面试·多级缓存·缓存架构