任务调度流程
1. 首先检测线程池运行状态,如果不是RUNNING,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
2. 如果workerCount < corePoolSize,则创建并启动一个线程来执行新提交的任务。<br>
3. 如果workerCount >= corePoolSize,且线程池内的阻塞队列未满,则将任务添加到该阻塞队列中。<br>
4. 如果workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满,则创建并启动一个线程来执行新提交的任务。<br>
5. 如果workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。<br>
任务缓冲[等待队列]
ArrayBlockingQueue
一个用数组实现的有界阻塞队列,此队列按照先进先出(FIFO)的原则对元素进行排序。支持公平锁和非公平锁
LinkedBlockingQueue
一个由链表结构组成的有界队列,次队列按照先进先出的原则对元素进行排序。此队列的长度默认为Integer.MAX_VALUE,所以默认创建的该队列有容量危险
PriorityBlockingQueue
一个支持线程优先级排序的无界队列,默认自然顺序排序,也可以自定义是先 compareTo()方法来执行元素排序规则,不能保证同优先级的顺序
DelayQueue
一个实现PriorityBlockingQueue实现延迟获取的无界队列,在创建元素时,可以指定多久才能从队列中获取当前元素。只有延时期满后才能从队列中获取元素。
SynchronousQueue
一个不存储元素的阻塞队列,每一个put操作必须等待take操作,否则不能添加元素。支持公平锁和非公平锁。<br>SynchronousQueue的一个使用场景是在线程池里:Executors.newCachedThreadPool()就使用了SynchronousQueue,这个线程池根据需要(新任务到来时)创建新的线程,如果有空闲线程则会重复使用,线程空闲了60秒后会被回收。
<b>LinkedTransferQueue</b>
一个由链表结构组成的无界阻塞队列,相当于其他队列,LinkedTransferQueue队列多了transfer和tryTransfer方法
<b>LinkedBlockingDeque</b>
一个由链表结构组成的双向阻塞队列,队列头部和尾部都可以添加和移动元素,多线程并发时,可以将锁的竞争最多降到一半。
任务拒绝
ThreadPoolExecutor.AbortPolicy
丢弃任务并抛出RejectedExecutionException异常。这是线程池默认的拒绝策略,在任务不能再提交的时候抛出异常,及时反馈程序运行状态。关键业务不建议是用;
ThreadPoolExecutor.DiscardPolicy
丢弃任务,但是不抛出异常;使用该策略可能会使我们无法发现系统的异常状态。建议非关键业务使用
ThreadPoolExecutor.DiscardOldestPolicy
丢弃队列最前面的任务,然后重新提交被拒绝的任务。
ThreadPoolExecutor.CallRunsPolicy
由调用线程(提交任务的线程)处理该任务。适合大量计算的任务类型去执行,多线程仅仅是增大吞吐量,最终必须要让每个任务都必须执行完毕;