一、概述
- 腾讯面试的时候被问到了,总结一下
二、分类
1、CachedThreadPool
-
它是一个可以无限扩大的线程池;
-
它比较适合处理执行时间比较小的任务;
-
corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大;
-
keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死;
-
采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。
public static ExecutorService newCachedThreadPool(){
return new ThreadPoolExecutor(
0, // 核心线程数
Integer.MAX_VALUE, // 最大线程数
60L,
TimeUnit.MILLISECONDS,
new SynchronousQueue<Runnable>());
}
1、SingleThreadExecutor
public static ExecutorService newSingleThreadExecutor(){
return new ThreadPoolExecutor(
1,
1,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
- 它只会创建一条工作线程处理任务;
- 采用的阻塞队列为LinkedBlockingQueue;
3、FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads){
return new ThreadPoolExecutor(
nThreads,
nThreads,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
-
它是一种固定大小的线程池;
-
corePoolSize和maximunPoolSize都为用户设定的线程数量nThreads;
-
keepAliveTime为0,意味着一旦有多余的空闲线程,就会被立即停止掉;但这里keepAliveTime无效;
-
由于阻塞队列是一个无界队列,因此永远不可能拒绝任务;
-
由于采用了无界队列,实际线程数量将永远维持在nThreads,因此maximumPoolSize和keepAliveTime将无效。
4、ScheduledThreadPool
-
它用来处理延时任务或定时任务。
-
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
- 创建并执行在给定延迟后启用的一次性操作。
-
ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
- 创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在
initialDelay
后开始执行,然后在initialDelay+period
后执行,接着在initialDelay + 2 * period
后执行,依此类推。
- 创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在
-
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
- 创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。
-
区别
-
scheduleAtFixedRate
方法的执行周期都是固定的,也就是,他是以上一个任务的开始执行时间作为起点,加上之后的 period 时间,调度下次任务。 -
scheduleWithFixedDelay
方法则是以上一个任务的结束时间作为起点,加上之后的 period 时间,调度下次任务。
-
(1)参数
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory, handler);
}
-
ScheduledThreadPoolExecutor
最多支持 3 个参数:核心线程数量,线程工厂,拒绝策略。 -
DelayedWorkQueue,是一个小根堆,是无界的,所以拒绝策略和最大线程数没啥用
(2)大致的执行流程
-
首先判断当前任务是否是周期性任务。如果线程池当前运行状态下不能执行周期性任务,则取消任务的执行,否则执行步骤2;
-
如果当前任务不是周期性任务,则直接调用FutureTask类的run方法执行任务,会设置执行结果,然后直接返回,否则执行步骤3;
-
如果当前任务是周期性任务,则调用FutureTask类的runAndReset方法执行任务,不会设置执行结果,然后直接返回,否则执行步骤4;
-
如果任务执行成功,则设置下次执行任务的时间,同时,将任务设置为重复执行。
这里有个小细节就是,只有再任务执行成功后,才会设置下次的执行时间,如果任务失败,这个周期性任务就不会执行了,其次,当 scheduleAtFixedRate 类型(以任务开始时间作为周期),的任务如果执行时间过长,超出设置的定时频率时长,本次任务执行完才开始下次任务,下次任务已经处于超时状态,会马上开始执行.
(3)小结
-
Rate
是从上一个任务的开始执行时间开始计算;Delay
是从上一个任务的结束时间开始计算。 -
如果任务本身的时间超过了间隔时间,那么这两种模式的间隔时间将会不一致
-
而任务的排序是通过
ScheduledFutureTask
的compareTo
方法排序的,规则是先比较执行时间,如果时间相同,再比较加入时间。 -
如果任务执行过程中异常了,那么将不会再次重复执行。因为
ScheduledFutureTask
的run
方法没有做catch
处理。