线程池分类以及7个参数,4种拒绝策略,5种运行状态

    技术2026-02-07  2

    线程池的运行过程

    1:当一个任务提交时,如果CorePool中的核心线程少于CorePoolSize,则创建一个新线程执行任务(需要全局锁)

    2:如果CorePool中没有空闲的线程,那么加入BlockingQueue等待核心线程拉取任务执行

    3:如果BlockingQueue已满,创建新线程后如果大于maximumPoolSize就跳转到4拒绝执行任务,如果小于就创建新线程执行任务(需要全局锁)

    4:四种不同的拒绝策略,通过rejectedExecution()方法执行。

    需要获取全局锁导致线程池的性能大大下降,应该尽量避免产生步骤1和步骤3

     

    使用Executors创建线程池 :但一般都不建议这么创建线程池

    package pool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * alibab开发手册以及工作中都是用 ThreadPoolExecutor 创建线程池, * 而不是用三大方法 newSingleThreadExecutor,newFixedThreadPool,newCachedThreadPool这三种 */ public class Demo01 { public static void main(String[] args) { // 单个线程 ExecutorService threadpool = Executors.newSingleThreadExecutor(); // 固定线程池大小 //ExecutorService threadpool = Executors.newFixedThreadPool(5); // 可伸缩的,遇强则强,遇弱则弱 ExecutorService threadpool = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { threadpool.execute(()->{ System.out.println(Thread.currentThread().getName()+" ok"); }); } threadpool.shutdown(); } }

     

    public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService( new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>() ) ); }

     

    public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>() ); } public LinkedBlockingQueue() { this(2147483647); }

     从源码中可以看出,newSingleThreadExecutor只允许创建单个线程,其他的线程都会被放在 LinkedBlockingQueue 阻塞队列中,而 newFixedThreadPool 能够创建自定义数量的线程数,同时,两种线程池都使用  LinkedBlockingQueue 阻塞队列,而阻塞队列的长度为 Integer.MAX_VALUE = 2147483647 ,过多的创建线程可能会造成内存溢出,也就是 OOM。

    public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>() ); }

     而在 newCachedThreadPool 线程池中将最大的线程池数量设置为 Integer.MAX_VALUE ,过多的创建线程的话也会造成一个 内存溢出,OOM。所以阿里云开发手册明确指出不建议使用这三种方式创建线程池,而是采取了自定义七大参数的方式创建线程池。

    七大参数的设置:

    package pool; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class Demo02 { public static void main(String[] args) { // corePoolSize核心线程池,默认开启的线程池数量 // maximumPoolSize 最大线程池, // keepAliveTime + TimeUnit.SECONDS 除核心线程池以外的3个线程池空闲时,保持 3 秒无别的线程后关闭 // ArrayBlockingQueue 阻塞队列候客区 // ThreadFactory线程工厂一般设为默认值不用改 // 线程池 4 大策略之一 超过 maximumPoolSize + 阻塞队列=线程最大承载时触发 // 1.AbortPolicy 报错 concurrent.RejectedExecutionException // 2.CallerRunsPolicy 哪来的去哪里,打发到 main 线程 // 3.DiscardOldestPolicy 即使线程数超过最大承载,也不会抛出异常,丢掉任务 // 4.DiscardPolicy 队列满了尝试会与最早的线程竞争,同时不会抛出异常 //池的最大大小如何设置(maximumPoolSize) //1.cpu 密集型,电脑或者处理器是几核就设置为几,保持cpu效率最高====6核12线程(设为12动态获取) //2.IO 密集型 根据 十分占用 io 资源的任务数决定。一般设为 2倍 任务数 System.out.println(Runtime.getRuntime().availableProcessors()); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 2, 5, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), //new ThreadPoolExecutor.AbortPolicy() //new ThreadPoolExecutor.CallerRunsPolicy() //new ThreadPoolExecutor.DiscardOldestPolicy() new ThreadPoolExecutor.DiscardPolicy() ); // 线程最大承载: queue + max for (int i = 0; i < 9; i++) { threadPoolExecutor.execute(()->{ System.out.println(Thread.currentThread().getName()+" ok"); }); } threadPoolExecutor.shutdown(); } }

    corePoolSize核心线程池,默认开启的线程池数量 maximumPoolSize 最大线程池, keepAliveTime + TimeUnit.SECONDS 除核心线程池以外的其他线程池空闲时,保持 3 秒(时间自己定义)无别的线程进来,3秒后关闭除核心线程池外的线程 ArrayBlockingQueue 阻塞队列候客区 ThreadFactory线程工厂一般设为默认值不用改

    阻塞队列

    阻塞队列-----四组api

     

    四大策略

    线程池 4 大策略, 超过 maximumPoolSize + 阻塞队列=线程最大承载时触发,线程数不达到最大承载时不会执行4个策略

    以下是4个策略分别执行的操作         1.AbortPolicy 报错 concurrent.RejectedExecutionException         2.CallerRunsPolicy  哪来的去哪里,若为主线程,打发到 main 线程         3.DiscardOldestPolicy 即使线程数超过最大承载,也不会抛出异常,丢掉任务         4.DiscardPolicy 队列满了尝试会与最早的线程竞争,同时不会抛出异常

     

    线程池的5种运行状态

     

    Running状态下添加处理线程

    Shutdown状态下不再接受新的线程,但仍会处理阻塞队列和线程池中的线程

    Stop状态下会中断正在处理的线程,不处理阻塞队列和其他

    Tidying状态下所有线程执行完毕,ctl记录的线程数为0

    Terminated状态下线程池终止

     

    最后简单介绍一下

    池的最大大小如何设置(即maximumPoolSize参数的设置)         1. CPU 密集型,电脑或者处理器是几核就设置为几,保持cpu效率最高====如我的电脑为6核12线程(设为12)

            动态获取:

    Runtime.getRuntime().availableProcessors()

            2. IO 密集型 根据 十分占用 io 资源的任务数决定。一般设为 2倍 密集任务数

    Processed: 0.032, SQL: 9