Java并发编程 - ScheduledThreadPoolEx
一、ScheduledThreadPoolExecutor初识
ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,在此基础上增加了延迟和定期执行任务的功能。
API描述如下:
ThreadPoolExecutor,它可另行安排在给定的延迟后运行命令,或者定期执行命令。需要多个辅助线程时,或者要求ThreadPoolExecutor具有额外的灵活性或功能时,此类要优于Timer。
延迟任务的执行时间不早于启用时间,但对于启用后何时开始没有任何实时保证。按照提交的先进先出 (FIFO) 顺序来启用那些被安排在同一执行时间的任务。
提交的任务在运行之前被取消,执行被抑制。 默认情况下,这样一个取消的任务在工作队列中不会自动删除,直到其延迟时间过去。虽然这样可以进一步检查和监控,但也可能导致取消任务的无限制保留。 为避免这种情况,请将setRemoveOnCancelPolicy(boolean)设置为true ,这将导致任务在取消时立即从工作队列中删除。
通过scheduleAtFixedRate或scheduleWithFixedDelay的任务的执行不重叠。 虽然不同的执行可以通过不同的线程来执行,先前执行的效果happen-before那些随后的那些的。
虽然此类继承自ThreadPoolExecutor,但是几个继承的调整方法对此类并无作用。特别是,因为它作为一个使用corePoolSize线程和一个无界队列的固定大小的池,所以调整maximumPoolSize 没有什么效果。此外,将corePoolSize设置为零或使用allowCoreThreadTimeOut几乎不是一个好主意,因为这可能会使池没有线程来处理任务,只要它们有资格运行。
扩展笔记:此类覆盖execute和submit方法以生成内部ScheduledFuture对象来控制每个任务的延迟和调度。若要保留功能性,子类中任何进一步重写的这些方法都必须调用超类版本,超类版本有效地禁用附加任务的定制。但是,此类提供替代受保护的扩展方法 decorateTask(为 Runnable 和 Callable 各提供一种版本),可定制用于通过 execute、submit、schedule、scheduleAtFixedRate 和 scheduleWithFixedDelay 进入的执行命令的具体任务类型。默认情况下,ScheduledThreadPoolExecutor 使用一个扩展 FutureTask 的任务类型。但是,可以使用下列形式的子类修改或替换该类型。
public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
static class CustomTask<V> implements RunnableScheduledFuture<V> { ... }
protected <V> RunnableScheduledFuture<V> decorateTask(
Runnable r, RunnableScheduledFuture<V> task) {
return new CustomTask<V>(r, task);
}
protected <V> RunnableScheduledFuture<V> decorateTask(
Callable<V> c, RunnableScheduledFuture<V> task) {
return new CustomTask<V>(c, task);
}
// ... add constructors, etc.
}
这个类使用特殊化ThreadPoolExecutor通过:
- 使用自定义任务类型ScheduledFutureTask处理任务,即使是那些不需要调度的任务(即使用ExecutorService execute而不是ScheduledExecutorService方法提交的任务),这些任务被视为延迟为零的延迟任务。
- 使用自定义队列(DelayedWorkQueue),它是无界DelayQueue的变体。与ThreadPoolExecutor相比,缺乏容量约束以及corePoolSize和maximumPoolSize实际上是相同的,简化了一些执行机制(参见DelayedExecute)。
- 支持可选的run-after-shutdown运行参数,这将导致覆盖关闭方法以删除和取消关闭后不应该运行的任务,以及当任务(重新)提交与关闭重叠时不同的重新检查逻辑。
- 任务修饰方法,以允许拦截和检测,这是必要的,因为子类不能覆盖提交方法以达到此效果。不过,这些对池控制逻辑没有任何影响。
二、ScheduledThreadPoolExecutor执行原理
延迟执行是怎么做到的:Worer从任务队列中取任务来执行,队列的头元素肯定是延迟时间最小的任务,通过判断延迟时间是否为0来决定任务的某次取操作是否可以取到元素,任务的延迟时间为0,则该任务可以被取出执行。通过取队列元素时的延迟时间检查来决定是否可以让任务出列,从而执行,这样就可以达到任务延迟执行的效果。
间隔得执行任务如何做到:我们知道任务是放入到任务队列中的,某任务如果出队列之后,那么该任务就不再在任务队列当中,它就不会再次被执行到了,要想达到重复间隔地执行一个任务,那么就应该在任务执行完成之后重新将它添加到队列里,重复这个过程,就可以达到任务间隔地执行的效果。