一、ThreadPoolExecutor
和java.util.concurrent.ThreadPoolExecutor差不多,但是实现了一个更高效的方法getSubmittedCount(),用于处理工作队列。
如果没有指定RejectedExecutionHandler,那么将会抛出RejectedExecutionException异常。
说一下这个方法:当一个线程提交过来,将会新建一个线程去执行,如果线程池满了,将会添加到工作队列,如果工作队列也满了,则会等待指定的时间(timeout),如果还不行,就抛出异常RejectedExecutionException
如何创建??
corePoolSize:核心线程数 maximumPoolSize:最大线程数。当阻塞队列满了,则会开启新的线程,但是不会超过maximumPoolSize keepAliveTime:对于大于corePoolSize的线程存活时间设置 unit:时间单位 workQueue:阻塞队列。jdk提供了很多种
简单介绍几个:
数组阻塞队列,按照FIFO规则,第一个就是等待时间最长的,最后一个就是新进来的。
基于链表结构的阻塞队列。吞吐量通常要高于ArrayBlockingQuene
一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene,因为他不需要存储。
具有优先级的无界阻塞队列,但是资源紧张可能发生OOM。不允许插入非可比对象
threadFactory :
创建线程的工厂,默认为DefaultThreadFactory
handler:拒绝策略
- AbortPolicy:直接抛出异常,默认策略;
- CallerRunsPolicy:用调用者所在的线程来执行任务;
- DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
- DiscardPolicy:直接丢弃任务;
当然也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。
创建线程池的方法通过Executor这个类创建
FixedThreadPool的工作队列为无界队列LinkedBlockingQueue
(队列容量为Integer.MAX_VALUE
), 这会导致以下问题:
线程池里的线程数量不超过corePoolSize
,这导致了maximumPoolSize
和keepAliveTime
将会是个无用参数 ,由于使用了无界队列, 所以FixedThreadPool永远不会拒绝, 即饱和策略失效
初始化的线程池中只有一个线程,如果该线程异常结束,会重新创建一个新的线程继续执行任务,唯一的线程可以保证所提交任务的顺序执行.由于使用了无界队列, 所以SingleThreadPool永远不会拒绝, 即饱和策略失效
- 线程池的线程数可达到Integer.MAX_VALUE,即2147483647,内部使用SynchronousQueue作为阻塞队列;
- 和newFixedThreadPool创建的线程池不同,newCachedThreadPool在没有任务执行时,当线程的空闲时间超过keepAliveTime,会自动释放线程资源,当提交新任务时,如果没有空闲线程,则创建新线程执行任务,会导致一定的系统开销;
关闭线程池:
- shutdown
将线程池里的线程状态设置成SHUTDOWN状态, 然后中断所有没有正在执行任务的线程. - shutdownNow
将线程池里的线程状态设置成STOP状态, 然后停止所有正在执行或暂停任务的线程.