前言

ScheduledThreadPoolExecutor可调度线程池,位于java.lang.concurrent包,在JDK1.5引入,由Doug Lea开发。它主要用来在给定的延迟之后运行任务,或者定期执行任务。
ScheduledThreadPoolExecutor的功能与Timer类似,但ScheduledThreadPoolExecutor功能更强大、更灵活。Timer对应的是单个后台线程,而ScheduledThreadPoolExecutor可以在构造函数中指定多个对应的后台线程数。

ScheduledThreadPoolExecutor

该类继承自ThreadPoolExecutor,查看继承关系图,是整个Executor框架中末端实现类,也是集大成者,即包含了ThreadPoolExecutor类中的功能,又在此基础上进行了延时、或定时调度增强。
ScheduledThreadPoolExecutor.png
延迟任务在它们被启用后立即执行,但没有任何实时保证在启用后它们何时开始,这些任务按照先进先出 (FIFO) 提交顺序执行。

构造方法

查看源码构造方法

  1. public ScheduledThreadPoolExecutor(int corePoolSize,
  2. ThreadFactory threadFactory,
  3. RejectedExecutionHandler handler) {
  4. super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
  5. new DelayedWorkQueue(), threadFactory, handler);
  6. }

需要注意的是,ScheduledThreadPoolExecutor的构造方法不像ThreadPoolExecutor可以对7个参数都进行设置,源码中所提供的构造方法最多仅支持对corePoolSize、threadFactory、handler的设置,关于其他参数默认值的说明:

  • maximumPoolSize参数被设置为Integer.MAX_VALUE
  • keepAliveTime参数被设置为0,意味着线程存在空闲会立即被回收
  • workQueue参数被设置为DelayedWorkQueue,DelayedWorkQueue是ScheduledThreadPoolExecutor内部实现的一个阻塞队列

当提交的任务在运行之前被取消时,一般来说,此类取消的任务不会自动从工作队列中删除,直到其延迟结束。可以通过方法setRemoveOnCancelPolicy设置为true,会使得任务在取消时立即从工作队列中删除。
尽管ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,尽量不要在运行期间通过父类引用来调整线程池的参数。例如:因为它充当使用corePoolSize线程和无界队列的固定大小的池,所以对maximumPoolSize的调整没有有用的效果。此外,将corePoolSize设置为零或使用allowCoreThreadTimeOut也是不推荐的,因为一旦它们有资格运行,这可能会使池没有线程来处理任务。

核心内部类

ScheduledThreadPoolExecutor有两个内部类DelayedWorkQueueScheduledFutureTask

DelayedWorkQueue

DelayedWorkQueue是基于类似于DelayQueue和PriorityQueue中的基于堆的数据结构,除了每个 ScheduledFutureTask还将其索引记录到堆数组中。这消除了在取消时查找任务的需要,大大加快了删除速度,从 O(n) 降低到 O(log n),并减少了在清除之前等待元素上升到顶部而可能发生的垃圾保留。但是因为队列也可能包含不是ScheduledFutureTasks的RunnableScheduledFutures,所以不能保证有这样的索引可用,在这种情况下回退到线性搜索。所有堆操作都必须记录索引更改,主要在siftUp和siftDown中。移除后,任务的heapIndex设置为 -1。注意,ScheduledFutureTasks最多只能在队列中出现一次(对于其他类型的任务或工作队列不必如此),因此由 heapIndex 唯一标识。
查看源码

  1. static class DelayedWorkQueue extends AbstractQueue<Runnable>
  2. implements BlockingQueue<Runnable>

ScheduledFutureTask

执行过程

ScheduledThreadPoolExecutor类重写execute和submit方法以生成内部ScheduledFuture对象来控制每个任务的延迟和调度,为了保留功能,在子类中对这些方法的任何进一步覆盖都必须调用超类版本,这有效地禁用了额外的任务定制。

调度方法

可延时执行异步任务和可周期执行异步任务方法

  1. /**这里传入的是实现Runnable接口的任务*/
  2. public ScheduledFuture<?> schedule(Runnable command,long delay, TimeUnit unit);
  3. /**这里传入的是实现Callable接口的任务*/
  4. public <V> ScheduledFuture<V> schedule(Callable<V> callable,long delay, TimeUnit unit);
  5. /**在initialDelay之后以上一个任务开始的时间计时,period时间过去后,检测上一个任务是否执行完毕,如果上一个任务执行完毕,则当前任务立即执行,如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行*/
  6. public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
  7. long initialDelay,
  8. long period,
  9. TimeUnit unit);
  10. /**是以上一个任务结束时开始计时,period时间过去后,立即执行*/
  11. public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
  12. long initialDelay,
  13. long delay,
  14. TimeUnit unit);