这是我参与8月更文挑战的第24天,活动详情查看:8月更文挑战
这个类在实际项目中基本不会被用到,因为有其他方案选择比如 quartz,但作为 JUC 包下的线程池,我们还是可以了解一下的
ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor,ScheduledThreadPoolExecutor的状态管理、入队操作、拒绝操作等都是继承于 ThreadPoolExecutor;ScheduledThreadPoolExecutor 主要是提供了周期任务和延迟任务相关的操作。
和 ThreadPoolExecutor 相比,它还具有以下几种特性:
- 使用专门的任务类型
ScheduledFutureTask
来执行周期任务,也可以接收不需要时间调度的任务(这些任务通过ExecutorService
来执行)。 - 使用专门的存储队列
DelayedWorkQueue
来存储任务,DelayedWorkQueue
是无界延迟队列DelayQueue
的一种。相比ThreadPoolExecutor
也简化了执行机制。 - 支持可选的
run-after-shutdown
参数,在池被关闭之后支持可选的逻辑来决定是否继续运行周期或延迟任务。并且当任务重新提交操作与shutdown
操作重叠时,复查逻辑也不相同。
二 ScheduledThreadPoolExecutor 详解
就 ScheduledThreadPoolExecutor 的运行逻辑而言,大致可以表述为:
- 首先将
Runnable/Callable
封装为ScheduledFutureTask
,延迟时间time
作为比较属性。 - 然后加入
DelayedWorkQueue
队列中,每次取出队首延迟最小的任务,超时等待,然后执行,如果执行所需时间相同则先提交的任务将被先执行,ScheduledFutureTask
的squenceNumber
变量小的先执行。 - 最后判断是否为周期任务,然后将其重新加入
DelayedWorkQueue
队列中。
1)运行机制
ScheduledThreadPoolExecutor 的执行主要分为两大部分:
- 当调用
ScheduledThreadPoolExecutor
的scheduleAtFixedRate()
方法或者**scheduleWirhFixedDelay()
** 方法时,会向ScheduledThreadPoolExecutor
的DelayQueue
添加一个实现了RunnableScheduledFuture
接口的ScheduledFutureTask
。 - 线程池中的线程从
DelayQueue
中获取ScheduledFutureTask
,然后执行任务。
ScheduledThreadPoolExecutor
** 为了实现周期性的执行任务,对 ****ThreadPoolExecutor
**做了如下修改:
- 使用
DelayQueue
作为任务队列; - 获取任务的方不同
- 执行周期任务后,增加了额外的处理
2)ScheduledThreadPoolExecutor 执行周期任务的步骤
- 线程 1 从
DelayQueue
中获取已到期的ScheduledFutureTask(DelayQueue.take())
。到期任务是指ScheduledFutureTask
的 time 大于等于当前系统的时间; - 线程 1 执行这个
ScheduledFutureTask
; - 线程 1 修改
ScheduledFutureTask
的 time 变量为下次将要被执行的时间; - 线程 1 把这个修改 time 之后的
ScheduledFutureTask
放回DelayQueue
中(DelayQueue.add()
)。