上面介绍的 TimingWheel 提供了添加延时任务和推进时间轮指针的操作,而具体执行延时任务的操作则交由定时器 SystemTimer 完成。SystemTimer 类实现了 Timer 特质,该特质描绘了定时器应该具备的基本方法。Timer 接口定义了管理延迟操作的方法,而 SystemTimer 是实现延迟操作的关键代码。
Timer 接口定义如下:
trait Timer {
/**
* Add a new task to this executor. It will be executed after the task's delay
* (beginning from the time of submission)
* @param timerTask the task to add
*/
// 将给定的定时任务插入到时间轮上,等待后续延迟执行
def add(timerTask: TimerTask): Unit
/**
* Advance the internal clock, executing any tasks whose expiration has been
* reached within the duration of the passed timeout.
* @param timeoutMs
* @return whether or not any tasks were executed
*/
// 向前推进时钟,执行已达过期时间的延迟任务
def advanceClock(timeoutMs: Long): Boolean
/**
* Get the number of tasks pending execution
* @return the number of tasks
*/
// 获取时间轮上总的定时任务数
def size: Int
/**
* Shutdown the timer service, leaving pending tasks unexecuted
*/
// 关闭定时器
def shutdown(): Unit
}
SystemTimer 类是 Timer 接口的实现类,它的定义如下:
class SystemTimer(executorName: String, // Purgatory 的名字
tickMs: Long = 1, // 默认时间格时间为 1 毫秒
wheelSize: Int = 20, // 默认时间格大小为 20
startMs: Long = Time.SYSTEM.hiResClockMs // 该 SystemTimer 定时器启动时间
) extends Timer {
// timeout timer
// 单线程的线程池用于异步执行定时任务
private[this] val taskExecutor = Executors.newFixedThreadPool(1, new ThreadFactory() {
def newThread(runnable: Runnable): Thread =
KafkaThread.nonDaemon("executor-"+executorName, runnable)
})
// 延迟队列保存所有Bucket,即所有TimerTaskList对象
private[this] val delayQueue = new DelayQueue[TimerTaskList]()
// 总定时任务数
private[this] val taskCounter = new AtomicInteger(0)
// 时间轮对象
private[this] val timingWheel = new TimingWheel(
tickMs = tickMs,
wheelSize = wheelSize,
startMs = startMs,
taskCounter = taskCounter,
delayQueue
)
// Locks used to protect data structures while ticking
// 维护线程安全的读写锁
private[this] val readWriteLock = new ReentrantReadWriteLock()
private[this] val readLock = readWriteLock.readLock()
private[this] val writeLock = readWriteLock.writeLock()
}
SystemTimer 类最重要的方法是 add 和 advanceClock 方法,因为它们是真正对外提供服务的。
add 方法
作用是将给定的定时任务插入到时间轮中进行管理。
def add(timerTask: TimerTask): Unit = {
// 获取读锁。在没有线程持有写锁的前提下,
// 多个线程能够同时向时间轮添加定时任务
readLock.lock()
try {
// 调用addTimerTaskEntry执行插入逻辑
addTimerTaskEntry(new TimerTaskEntry(timerTask, timerTask.delayMs + Time.SYSTEM.hiResClockMs))
} finally {
// 释放读锁
readLock.unlock()
}
}
// add 方法就是调用 addTimerTaskEntry 方法执行插入动作
private def addTimerTaskEntry(timerTaskEntry: TimerTaskEntry): Unit = {
// 视timerTaskEntry状态决定执行什么逻辑:
// 1. 未过期未取消:添加到时间轮
// 2. 已取消:什么都不做
// 3. 已过期:提交到线程池,等待执行
// TimingWheel 的 add 方法会在定时任务已取消或已过期时,返回 False,否则,该方法会将定时任务添加到时间轮,然后返回 True。
if (!timingWheel.add(timerTaskEntry)) {
// Already expired or cancelled
// 定时任务未取消,说明定时任务已过期
// 否则timingWheel.add方法应该返回True
if (!timerTaskEntry.cancelled)
taskExecutor.submit(timerTaskEntry.timerTask)
}
}
advanceClock 方法
顾名思义,它的作用是驱动时钟向前推进
/** 将延时任务重新添加到时间轮中 */
private[this] val reinsert = (timerTaskEntry: TimerTaskEntry) => addTimerTaskEntry(timerTaskEntry)
/*
* Advances the clock if there is an expired bucket. If there isn't any expired bucket when called,
* waits up to timeoutMs before giving up.
*/
def advanceClock(timeoutMs: Long): Boolean = {
// 获取delayQueue中下一个已过期的Bucket
var bucket = delayQueue.poll(timeoutMs, TimeUnit.MILLISECONDS)
if (bucket != null) {
// 获取写锁
// 一旦有线程持有写锁,其他任何线程执行add或advanceClock方法时会阻塞
writeLock.lock()
try {
while (bucket != null) {
// 推动时间轮向前"滚动"到Bucket的过期时间点
timingWheel.advanceClock(bucket.getExpiration())
// 将该Bucket下的所有定时任务重写回到时间轮
bucket.flush(reinsert)
// 读取下一个Bucket对象
bucket = delayQueue.poll()
}
} finally {
// 释放写锁
writeLock.unlock()
}
true
} else {
false
}
}