
线程池的作用
面向对象程序开发中,对象的创建需要耗费一定的资源。JAVA中也是类似的,JVM试图跟踪每一个对象,以便在对象销毁时进行垃圾回收。线程池技术重点关注如何缩短线程创建与销毁时间。
ThreadPoolExecutor
1 |
public (int corePoolSize, |
corePoolSize线程池中核心线程数maximumPoolSize线程池维护的最大线程数keepAliveTime线程池容许线程空闲的时间unitkeepAliveTime参数的单位workQueue任务处理队列ArrayBlockingQueue基于数组的有界阻塞队列LinkedBlockingQueue基于链表的阻塞队列SynchronizesQueue每个插入操作要等另一个线程调用移除操作,否则插入操作一直处于阻塞状态PriorityBlockingQueue具有优先级的无界阻塞队列
threadFactory创建线程时的工厂。线程工厂有两种选择,DefaultThreadFactory与PrivilegedThreadFactory。DefaultThreadFactory创建一个默认优先级的线程,PrivilegedThreadFactory创建权限控制的线程。handler超出线程与队列容量时的处理策略,有以下四种:ThreadPoolExecutor.AbortPolicy抛RejectedExecutionException异常。ThreadPoolExecutor与ScheduledThreadPoolExecutor线程池的默认处理策略。ThreadPoolExecutor.CallerRunsPolicy重复尝试添加当前任务。ThreadPoolExecutor.DiscardOldestPolicy抛弃旧任务,执行当前任务。ThreadPoolExecutor.DiscardPolicy直接抛弃旧任务。
线程池中添加任务
一个任务通过execute方法添加到线程池中,这个任务必须是一个Runable对象,当任务被执行时,调用的是run方法。
当一个任务被添加到线程池中时,通常经历以下几个步骤:
- 线程池中的线程小于
corePoolSize,创建新的线程来处理新任务。 - 线程池中的线程大于等于
corePoolSize,但是缓冲队列workQueue未满,那么将任务加入缓冲队列。 - 线程池中的线程大于等于
corePoolSize,缓冲队列workQueue已满,并且线程数量未超过最大容量maximumPoolSize,创建新的线程来处理新任务。 - 线程池中的线程大于等于
corePoolSize,缓冲队列workQueue已满,线程数量超过了最大容量maximumPoolSize,采用handler的策略来处理。
常用线程池
Executor类中提供了几种常用的静态工厂:
newSingleThreadExecutor
1 |
public static ExecutorService newSingleThreadExecutor(){} |
创建只有一个线程工作的线程池,相当于单线程串行执行任务。如果这个唯一的线程由于异常而结束,会有一个新的线程来替代它。此线程池保证任务按照提交的次序顺序执行。
newCachedThreadPool
1 |
public static ExecutorService newCachedThreadPool() {} |
创建一个缓存线程池,若线程池的大小大于任务执行所需的线程数,那么空闲时间大于60s的线程将被回收。若有新任务提交,线程池会动态创建新的线程来进行处理。
newFixedThreadPool
1 |
public static ExecutorService newFixedThreadPool(){ |
创建一个指定大小的线程池,每次提交任务,都会创建一个新的线程,直到线程数量达到线程池的最大值,以后新提交的任务都会存放在等待队列中。若线程池中的线程因异常而退出,线程池会补充一个线程。
newSingleThreadScheduledExecutor
1 |
public static ScheduledExecutorService newSingleThreadScheduledExecutor() { |
创建一个单线程的线程池,该线程池还支持定时与周期性执行任务。
newScheduledThreadPool
1 |
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { |
类似newCachedThreadPool,创建一个缓冲线程池,该线程池同时还支持定时与周期性执行任务。
有界队列
对于有界队列,有任务提交时,采用以下处理方式:
- 若线程池中线程数小于
corePoolSize,直接新建一个线程,立即处理。 - 若线程池中线程数大于等于
corePoolSize,且任务处理队列workQueue未满,则将任务存入队列中。 - 若线程池中线程数大于等于
corePoolSize,任务处理队列workQueue已满,且未超过最大线程数maximumPoolSize,则尝试新建一个线程进行紧急处理。 - 若以上三步都无法处理,则执行拒绝策略。
无界队列
相比于有界队列,无界队列不存在任务入队出错的情况,具体处理方式如下:
- 若线程池中线程数小于
corePoolSize,直接新建一个线程,立即处理。 - 若线程池中线程数大于等于
corePoolSize,则将任务存入任务处理队列workQueue中。若任务创建与处理速度差异很大,则无界队列会保持快速增长,直到耗尽系统内存。
PS:说LinkedBlockingQueue是无界队列是不恰当的,其长度是Integer.MAX_VALUE。
线程池初始化
默认情况下,创建线程池后,线程池中是没有线程的,需要提交任务才会创建线程。
当然如果需要创建线程池后就立即创建线程,可以使用下面两个方法:
- prestartCoreThread() 初始化一个核心线程
- prestartAllCoreThreads() 初始化所有核心线程
execute与submit区别
execute与submit都是向线程池提交任务,但是submit会返回一个future,通过future可以获取任务运行的结果。




近期评论