引言
在许多业务场景中,我们都会碰到延迟任务,定时任务这种需求。特别的,在网络连接的场景中,常常会出现一些超时控制。由于服务端的连接数量很大,这些超时任务的数量往往也是很庞大的。实现对大量任务的超时管理并不是一个容易的事情。
本章我们将介绍几种用于实现超时任务的数据结构,并且最后分析 Netty 在超时任务上采取的结构和代码。
JDK 原生提供的超时任务支持
java.util.Timer
JDK 在 1.3 的时候引入了 Timer 数据结构用于实现定时任务。Timer 的实现思路比较简单,其内部有两个主要属性:
- TaskQueue:定时任务抽象类 TimeTask 的列表。
- TimerThread:用于执行定时任务的线程。
Timer 结构还定义了一个抽象类 TimerTask 并且继承了 Runnable 接口。业务系统实现了这个抽象类的 run 方法用于提供具体的延时任务逻辑。
TaskQueue 内部采用大顶堆的方式,依据任务的触发时间进行排序。而 TimerThread 则以死循环的方式从 TaskQueue 获取队列头,等待队列头的任务的超时时间到达后触发该任务,并且将任务从队列中移除。
Timer 的数据结构和算法都很容易理解。所有的超时任务都首先进入延时队列。后台超时线程不断的从延迟队列中获取任务并且等待超时时间到达后执行任务。延迟队列采用大顶堆排