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

相关推荐
工业甲酰苯胺2 分钟前
Spring Boot 整合 MyBatis 的详细步骤(两种方式)
spring boot·后端·mybatis
严文文-Chris15 分钟前
【设计模式-享元】
android·java·设计模式
Flying_Fish_roe32 分钟前
浏览器的内存回收机制&监控内存泄漏
java·前端·ecmascript·es6
新知图书35 分钟前
Rust编程的作用域与所有权
开发语言·后端·rust
c#上位机41 分钟前
C#事件的用法
java·javascript·c#
【D'accumulation】1 小时前
典型的MVC设计模式:使用JSP和JavaBean相结合的方式来动态生成网页内容典型的MVC设计模式
java·设计模式·mvc
wn5311 小时前
【Go - 类型断言】
服务器·开发语言·后端·golang
试行2 小时前
Android实现自定义下拉列表绑定数据
android·java
茜茜西西CeCe2 小时前
移动技术开发:简单计算器界面
java·gitee·安卓·android-studio·移动技术开发·原生安卓开发
救救孩子把2 小时前
Java基础之IO流
java·开发语言