ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,整体的内部结构和ThreadPoolExecutor是一样的。有一个重点的不同就是阻塞队列使用的是DelayedWorkQueue。他可以根据我们设置的时间延迟来对任务进行排序,让任务按照时间顺序进行执行,和MessageQueue非常像。
ScheduledThreadPoolExecutor实现了ScheduledExecutorService接口,有一系列可以设置延时任务、周期任务的api。
定时周期任务我们会想到Timer这个框架。这里简单做个对比:
Timer是系统时间敏感的,他会根据系统时间来触发任务
Timer内部只有一个线程,可能会造成执行任务阻塞无法按时执行;而ScheduledThreadPoolExecutor可以创建多个线程来执行任务
Timer遇到异常时会直接抛出,线层终止;而ScheduledThreadPoolExecutor有一个更加完善的异常处理机制。
参数配置先看到ShcduledhreadPoolExecutor的构造器:
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue(), threadFactory, handler); }ScheduledThreadPoolExecutor有几个构造器,参数数量最多的是上面这个。父类是ThreadPoolExecutor,所以这里是直接调用到ThreadPoolExecutor的构造器:
核心线程数:这个由我们自己传入参数设定
线程数上限:这个设置Integer.MAX_VALUE,可以认为是没有上限
keepAliveTime:10毫秒,基本上只要线程进入空闲状态马上就会被回收
阻塞队列:DelayedWorkQueue在上面介绍过了,可以设置延迟时间的阻塞队列
线程工厂和拒绝策略由开发者自定义
可以看到ShceduledThreadPoolExecutor的配置还是比较简单的,重点在于他的延时阻塞队列可以设置延时任务;keepAliveTime时间的设置让空闲的线程马上就会被回收。
线程池的使用ScheduledThreadPoolExecutor有ThreadPoolExecutor的接口,同时还包含了一些定时任务的接口:
schedule:传入一个任务和延迟的时间,在延迟时间之后开始执行任务
scheduleAtFixedRate:设置固定时间点指定任务。传入两个时间,第一次执行在延迟初始化的时间后;之后每隔指定时间执行一次。
scheduledWithFixedDelay:在初始延迟之后,每次执行之后延迟指定时间再次执行。
重点就是上面的三个方法的使用,其他的和ThreadPoolExecutor类似。
Executors线程池配置的参数很多,框架内置了一些已经配置好参数的线程池,如果懒得去配置参数,可直接使用内置的线程池,可以使用Executors.newXXX方法来构建。
ThreadPoolExecutor有三个配置好参数的线程池:FixedTthreadPool、CacheThreadPool、SingleThreadExecutor。ScheduledThreadPoolExecutor有两个配置好参数的线程池:ScheduledThreadPoolExecutor和SingleThreadScheduledExecutor。
我们看一下这些线程池:
FixedThreadPool public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); }这类线程池只有核心线程,数量固定且不会被回收,等待队列的长度没有上限。
这个线程池的特点就是线程数量固定,适用于负载较重的服务器,可以通过这种线程池来限制线程数量;线程不会被回收,也有比较高的响应速度。
但是等待队列没有上限,在任务过多时有可能发生OOM。
CacheThreadPool public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }这类线程池没有核心线程,而且线程数量上限为Integer.MAX_VALUE,可以认为没有上限。等待队列没有长度,每一个任务到来都会分配一个线程来执行。
这类线程池的特点就是每个任务都会被马上执行,在任务数量过大时可能会创建大量的线程导致系统OOM。但是在一些任务数量多但执行时间短的情景下比较适用。
SingleThreadExecutor public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory)); }