ScheduledThreadPoolExecutor继承了ThreadPoolExecutor和实现了ScheduledExecutorService接口。是用于执行延时任务和周期任务的线程池。
ScheduledThreadPoolExecutor的延时执行的实现是通过队列DelayedWorkQueue和ScheduledFutureTask来实现。
核心内部类
ScheduledFutureTask
ScheduledFutureTask用于封装定期任务和获取任务结果。
1 | ScheduledFutureTask(Runnable r, V result, long ns, long period) { |
ScheduledFutureTask的继承关系
看继承关系可以看到,父接口有一个Delayed接口。Delayed接口继承了Comparable接口。这两个方法非常重要。DelayedWorkQueue队列会根据compareTo的排序规则给队列元素排序,将执行时间早的任务放在队头。getDelay方法用于判断任务是否到了执行时间。下面是实现方法。
1 | //还需要延迟多久 |
DelayedWorkQueue
用于存储延迟执行的任务的阻塞队列。内部用数组实现,初始容量16。容量不足时会扩容50%。
queue数组表示一个二叉堆。
当父节点的键值总是大于或等于任何一个子节点的键值时为最大堆。 当父节点的键值
总是小于或等于任何一个子节点的键值时为最小堆
1
2 private RunnableScheduledFuture<?>[] queue =
new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
入队
入队的任务是ScheduledFutureTask对象,会通过ScheduledFutureTask的compareTo进行任务的比较。将数组queue排列成最小堆。最早执行的任务(getDelay最小的)是根节点queue[0]。
1 | public boolean offer(Runnable x) { |
数组queue是一个二叉堆,新加入的元素通过堆排序找到合适的位置插入。
1 | private void siftUp(int k, RunnableScheduledFuture<?> key) { |
出队
queue数组表示二叉堆,queue[0]元素是根节点。判断根节点是否到了执行时间。
1 | public RunnableScheduledFuture<?> take() throws InterruptedException { |
ScheduledThreadPoolExecutor任务执行流程
任务提交
ScheduledThreadPoolExecutor的schedule方法很多,都差不多。以scheduleAtFiexedRate为例子。
1 | public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, |
任务执行
执行任务时调用ThreadPoolExecutor的runWorker方法。
1 | final void runWorker(Worker w) { |
ScheduledFutureTask的run方法
1 | public void run() { |