• Java并发编程系列33:线程池ThreadPoolExecutor工作流程


    线程池ThreadPoolExecutor工作流程

    Java线程池主要是用于合理创建线程,减少线程创建销毁频率(线程复用、线程资源管理),最大限度利用CPU性能。

    线程池(这里说的是ThreadPoolExecutor)工作流程分3步:

    1、创建线程池

    2、线程池对象创建线程执行任务

    3、关闭线程池

    1、线程池参数

    序号

    参数名

    参数说明

    1

    corePoolSize

    核心线程数

    2

    maximumPoolSize

    最大线程数

    3

    keepAliveTime

    非核心线程空闲状态下线程回收时间

    4

    unit

    keepAliveTime 的时间单位

    5

    workQueue

    任务队列,是一个阻塞队列,当线程数已达到核心线程数,会将任务存储在阻塞队列

    6

    RejectedExecutionHandler

    拒绝策略

    ThreadPoolExecutor构造方法:

        public ThreadPoolExecutor(int corePoolSize,

                                  int maximumPoolSize,

                                  long keepAliveTime,

                                  TimeUnit unit,

                                  BlockingQueue workQueue,

                                  RejectedExecutionHandler handler) {}

    2、线程池工作流程

    2.1、创建线程池

            int threadNum=11;

    int taskNum=10;

            //创建一个自定义线程池对象

            ThreadPoolExecutor  exs = new ThreadPoolExecutor(5, threadNum, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2));

    corePoolSize=5       //核心线程数=5

    maximumPoolSize=11   //最大线程数=11

    keepAliveTime=0      //非核心线程空闲状态下线程回收时间=0

    默认拒绝策略:AbortPolicy  //超出后抛弃任务

    线程池大小= 最大线程数 + 阻塞队列大小=11+2=13

    2.2、线程池对象创建线程执行任务

            for(int i=0;i

                //通过 ExecutorService 对象的 execute 方法将任务添加到线程去执行

                exs.execute(new Runnable1());

                System.out.println("---核心线程数:" + exs.getCorePoolSize()+",线程池中线程数目:"+exs.getPoolSize()+",---队列中等待执行的任务数目:"+ exs.getQueue().size());

            }

    threadPoolExecutor 执行 execute 方法分下面4中情况

    1)当前线程< coolPoolSize时,直接创建线程执行

    当一个任务通过 submit 或者 execute 方法提交到线程池的时候,如果当前池中线程数(包括闲置线程)小于 coolPoolSize,则创建一个线程执行该任务。

    2)当前线程>= coolPoolSize时,入队

    如果当前线程池中线程数已经达到 coolPoolSize,则将任务放入等待队列。

    3) 当前线程>= coolPoolSize,但小于maximumPoolSize时,创建非核心线程执行

    如果任务不能入队,说明等待队列已满,若当前池中线程数小于 maximumPoolSize,则创建一个临时线程(非核心线程)执行该任务。

    4)如果当前池中线程数已经等于 maximumPoolSize,此时无法执行该任务,根据拒绝执行策略处理。

    注意:当池中线程数大于 coolPoolSize,超过 keepAliveTime 时间的闲置线程会被回收掉。回收的是非核心线程,核心线程一般是不会回收的。

    如果设置 allowCoreThreadTimeOut(true),则核心线程在闲置 keepAliveTime 时间后也会被回收。

    任务队列是一个阻塞队列,线程执行完任务后会去队列取任务来执行,如果队列为空,线程就会阻塞,直到取到任务。

    4种拒绝策略RejectedExecutionHandler

    • AbortPolicy:丢弃任务,抛出运行时异常
    • CallerRunsPolicy:由提交任务的线程来执行任务
    • DiscardPolicy:丢弃这个任务,但是不抛异常
    • DiscardOldestPolicy:从队列中剔除最先进入队列的任务,然后再次提交任务

    线程池执行任务的流程图:

     

    2.3、关闭线程池

    exs.shutdown();

    线程池有2种关闭方法:

    shutdown():线程池拒接收新提交的任务,同时等待线程池里的任务执行完毕后关闭线程池。

    shutdownNow() :线程池拒接收新提交的任务,同时立马关闭线程池,线程池里的任务不再执行,并能获取未被执行的任务。

    3、示例Demo

    1. package runnable;
    2. import java.util.concurrent.*;
    3. //定义一个 Runnable接口的实现类
    4. class Runnable1 implements Runnable{
    5. @Override
    6. public void run() {
    7. try {
    8. System.out.println(Thread.currentThread().getName()+" 在运行任务");
    9. Thread.sleep(2000);
    10. } catch (InterruptedException e) {
    11. e.printStackTrace();
    12. }
    13. }
    14. }
    15. public class ThreadPoolDemo {
    16. public static void main(String[] args){
    17. int threadNum=9;
    18. int taskNum=10;
    19. //创建一个自定义线程池对象
    20. ThreadPoolExecutor exs = new ThreadPoolExecutor(5, threadNum, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2));
    21. for(int i=0;i
    22. //通过 ExecutorService 对象的 execute 方法将任务添加到线程去执行
    23. exs.execute(new Runnable1());
    24. System.out.println("---核心线程数:" + exs.getCorePoolSize()+",线程池中线程数目:"+exs.getPoolSize()+",---队列中等待执行的任务数目:"+ exs.getQueue().size());
    25. }
    26. exs.shutdown();
    27. }
    28. }

    执行结果分析:

    1. 超过核心线程数,有两个任务入阻塞队列,最后线程1和3执行完成后,这两个任务由线程1和3来执行。
    2. 超过队列数后,创建了非核心线程6,7,8来执行任务。

     参考:https://blog.csdn.net/zhengzhaoyang122/article/details/110789385

  • 相关阅读:
    imu测试--UDP、PTP
    Android解析异步消息机制——Android筑基
    JS十大设计模式(2/2)
    2023版 STM32实战5 基本定时器中断
    Postman汉化教程
    【324. 摆动排序 II】
    【Python从0到1】第四篇:使用库
    MySQL EXPLAIN查看执行计划
    PSI项目介绍
    dedecms织梦快照被挟持和篡改入侵漏洞修复
  • 原文地址:https://blog.csdn.net/fen_fen/article/details/126049894