线程池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 拒绝创建;

相关推荐
间彧6 分钟前
Redis Stream相比阻塞列表和发布订阅有哪些优势?适合什么场景?
后端
间彧12 分钟前
Redis阻塞弹出和发布订阅模式有什么区别?各自适合什么场景?
后端
苏三说技术19 分钟前
统计接口耗时的6种常见方法
后端
SimonKing25 分钟前
Mybatis-Plus的竞争对手来了,试试 MyBatis-Flex
java·后端·程序员
光军oi31 分钟前
JAVA全栈JVM篇————初识JVM
java·开发语言·jvm
我命由我1234536 分钟前
PDFBox - PDFBox 加载 PDF 异常清单(数据为 null、数据为空、数据异常、文件为 null、文件不存在、文件异常)
java·服务器·后端·java-ee·pdf·intellij-idea·intellij idea
渣哥41 分钟前
当容器里有多个 Bean,@Qualifier 如何精准定位?
javascript·后端·面试
7哥♡ۣۖᝰꫛꫀꪝۣℋ43 分钟前
Spring Boot
java·spring boot·后端
Moniane1 小时前
C++深度解析:从核心特性到现代编程实践
java·开发语言·jvm
攻城狮CSU1 小时前
C# 数据加载专题 之泛型序列化
java·servlet·c#