一、执行流程
ThreadPoolExecutor是Java标准库的线程池,Executors本质上是对其进行封装后的类。
先来认识一下ThreadPoolExecutor的构造方法:
ThreadPoolExecutor的构造方法
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory, RejectedExecutionHandler)
我们主要看一下最后一个构造方法,这个方法的参数是最为齐全的~
参数一:int corePoolSize
表示线程池的核心线程数量,核心线程即使处于空闲状态也不会被销毁。
参数二:int maximumPoolSize
表示线程池的最大线程数量,最大线程数量 = 核心线程数 + 临时线程数;临时线程处于空闲状态达到一定时间,就会被销毁。
参数三:long keepAliveTime
表示临时线程可以处于空闲状态的最长时间。
参数四:TimeUnit unit
表示参数三的时间单位 ,可以设置为纳秒、微秒、毫秒、秒、分钟等单位。
参数五:BlockingQueue workQueue
给线程池传入一个工作队列。
参数六:ThreadFactory
ThreadFactory是一个接口,描述了线程的创建方式,我们可以通过ThreadFactory对象手动来指定如何创建线程。
参数七:RejectedExecutionHandler 表示线程池的拒绝策略
示例:创建一个核心线程数为5,最大线程数为10,任务队列容量为100的线程池
认识了构造方法,我们才能理解它的执行流程~
ThreadPoolExecutor的执行流程是这样的:
1、当线程池中新加入一个任务时,先判断核心线程数是否达到最大值,如果为false则创建一个核心线程执行任务,如果为true执行第二步;
2、判断当前任务队列是否已满,如果为false,则将任务加入到队列中等待执行;如果为true,则判断当前线程数是否达到最大线程数;
3、如果当前线程数没有达到最大线程数,则创建临时线程来执行任务,如果达到最大线程数,则执行拒绝策略。
二、拒绝策略
从上图可以看出,拒绝策略指的是线程池中线程数量达到最大值,任务队列为满时,来了新任务的处理方式。
标准库中提供了以下几种拒绝策略:
1、ThreadPoolExecutor.AbortPolicy
抛出一个RejectedExecutionException异常来拒绝执行任务:
2、ThreadPoolExecutor.CallerRunsPolicy
新加入的任务由线程池的调用线程来执行;
如果调用线程被销毁了,那么新加入的任务就会被丢弃。
3、ThreadPoolExecutor.DiscardOdestPolicy
丢弃当前还未被执行的任务中的第一个任务,然后重新执行新加入的任务;如果线程池的调用线程被销毁了,那么新加入的任务就会被丢弃。
4、ThreadPoolExecutor.DiscardPolicy
直接丢弃新加入的任务。