一 SystemTimer
Kafka中定时器的实现,它在时间轮的基础上添加了执行到期任务,阻塞等待最近到期任务的功能
tickMs: Long 时间格
executorName: String 线程名字
wheelSize: Int 时间轮
startMs: Long 创建时间
taskExecutor:ExecutorService 固定线程池,由此线程执行定时到期任务
delayQueue:DelayQueue[TimerTaskList] 各个层级时间轮公用的DelayQueue,主要作用是阻塞推进时间轮指针的线程ExpiredOperationReaper,等待最近到期的任务
taskCounter:AtomicInteger 各个层级时间轮公用的任务个数计数器
timingWheel:TimingWheel 层级时间轮中对底层的时间轮
readWriteLock:ReentrantReadWriteLock 用来同步时间轮指针的currentTime修改后的读写锁
add 再添加过程中,如果发现任务已经到期,则将任务提交到taskExecutor执行;如果任务未到期,则调用TimerWheel.add提交到时间轮等待后期执行
def add(timerTask:TimerTask): Unit = {
readLock.lock()
try {
// 将TimerTask封装成TimerTaskEntry,并计算到期时间
addTimerTaskEntry(newTimerTaskEntry(timerTask,timerTask.delayMs + SystemTime.hiResClockMs))
} finally {
readLock.unlock()
}
}
addTimerTaskEntry 向时间轮提交添加任务
private def addTimerTaskEntry(timerTaskEntry: TimerTaskEntry): Unit = {
// 向时间轮提交添加任务失败,任务可能到期或者取消
if (!timingWheel.add(timerTaskEntry)) {
// 如果不是取消,则提交给线程池
if (!timerTaskEntry.cancelled)
taskExecutor.submit(timerTaskEntry.timerTask)
}
}
advanceClock 完成了时间轮指针的推进,同时对到期TimerTaskList的任务进行处理;如果TimerTaskList到期,但其中某些任务未到期 会将未到期的任务进行降级,添加到低层次的时间轮继续等待,如果任务到期了则提交到taskExecutor执行
def advanceClock(timeoutMs: Long): Boolean = {
// 从队列取出第一个元素,如果不能立即取出,可以等待timeoutMs毫秒再取,还是没有取到返回空
var bucket = delayQueue.poll(timeoutMs, TimeUnit.MILLISECONDS)
if (bucket != null) {// 表示在队列阻塞期间有任务到期
writeLock.lock()
try {
while (bucket != null) {
// 尝试推进当前时间轮的指针,同时也会尝试推进上层时间轮的指针,随着当前时间轮的不断推进,上层时间轮指针早晚会被推进成功
timingWheel.advanceClock(bucket.getExpiration())
// 调用reinsert,尝试将bucket中的任务重新添加到时间轮,此过程可能会提交到taskExecutor线程执行,未到期的任务进行降级
bucket.flush(reinsert)
bucket = delayQueue.poll()// 非阻塞的取出第一个元素
}
} finally {
writeLock.unlock()
}
true
} else {
false
}
}
二 TimerTaskList源码分析
private[timer] class TimerTaskList(taskCounter: AtomicInteger) extends Delayed {
// TimerTaskList 是一个双向的循环列表
// root.next 指向下一个
// root.prev 指向前一个
// 创建一个TimerTaskEntry 节点,初始化next prev 都等于root,这是一个虚拟的TimerTaskEntry,并不存储任何任务
private[this] val root = new TimerTaskEntry(null, -1)
root.next = root
root.prev = root
// 初始化该环形双向链表到期时间
private[this] val expiration = new AtomicLong(-1L)
// 设置该环形双向链表的到期时间,如果里面的任务到期则交给线程执行,否则进行降级
// 如果到期时间改变返回true
def setExpiration(expirationMs: Long): Boolean = {
expiration.getAndSet(expirationMs) != expirationMs
}
// 获取该环形双向链表的到期时间
def getExpiration(): Long = {
expiration.get()
}
// Apply the supplied function to each of tasks in this list
def foreach(f: (TimerTask)=>Unit): Unit = {
synchronized {
// 获取下一个TimerTaskEntry节点
var entry = root.next
// 如果TimerTaskEntry不等于root
while (entry ne root) {
// 获取下一个TimerTaskEntry下一个节点
val nextEntry = entry.next
// 如果下一个entry没有被取消,调用函数f
if (!entry.cancelled) f(entry.timerTask)
entry = nextEntry
}
}
}
// Add a timer task entry to this list
def add(timerTaskEntry: TimerTaskEntry): Unit = {
var done = false
while (!done) {
// Remove the timer task entry if it is already in any other list
// We do this outside of the sync block below to avoid deadlocking.
// We may retry until timerTaskEntry.list becomes null.
// 如果其他TimerTaskList也存在这个timerTaskEntry则删除它,避免死锁
timerTaskEntry.remove()
synchronized {
timerTaskEntry.synchronized {
// timerTaskEntry所在的TimerTaskList如果为空
if (timerTaskEntry.list == null) {
// put the timer task entry to the end of the list. (root.prev points to the tail entry)
// 把当前timerTaskEntry放在队列尾部,并且前一个节点指向尾部的entry,下一个节点指向头部也
val tail = root.prev
timerTaskEntry.next = root
timerTaskEntry.prev = tail
timerTaskEntry.list = this
tail.next = timerTaskEntry
root.prev = timerTaskEntry
taskCounter.incrementAndGet()// 时间轮任务总数+1
done = true
}
}
}
}
}
// 从TimerTaskLKList删除指定的TimerTaskEntry
def remove(timerTaskEntry: TimerTaskEntry): Unit = {
synchronized {
timerTaskEntry.synchronized {
// 如果timerTaskEntry所在的TimerTaskList就是当前的TimerTaskList
// 删除这个timerTaskEntry
if (timerTaskEntry.list eq this) {
timerTaskEntry.next.prev = timerTaskEntry.prev
timerTaskEntry.prev.next = timerTaskEntry.next
timerTaskEntry.next = null
timerTaskEntry.prev = null
timerTaskEntry.list = null
taskCounter.decrementAndGet()// 时间轮任务总数-1
}
}
}
}
// 删除所有的task entry,并且每一个task entry应用函数f
def flush(f: (TimerTaskEntry)=>Unit): Unit = {
synchronized {
var head = root.next
while (head ne root) {
remove(head)
f(head)
head = root.next
}
expiration.set(-1L)
}
}
def getDelay(unit: TimeUnit): Long = {
unit.convert(max(getExpiration - SystemTime.hiResClockMs, 0), TimeUnit.MILLISECONDS)
}
def compareTo(d: Delayed): Int = {
val other = d.asInstanceOf[TimerTaskList]
if(getExpiration < other.getExpiration) -1
else if(getExpiration > other.getExpiration) 1
else 0
}
}
三 TimerTaskEntry源码分析
private[timer] class TimerTaskEntry(val timerTask: TimerTask, val expirationMs: Long) extends Ordered[TimerTaskEntry] {
@volatile
var list: TimerTaskList = null // TimerTaskEntry所在的TimerTaskList双向循环链表
var next: TimerTaskEntry = null // 下一个TimerTaskEntry
var prev: TimerTaskEntry = null // 前一个TimerTaskEntry
// 给当前TimerTaskEntry设置timer task
if (timerTask != null) timerTask.setTimerTaskEntry(this)
// 当前timer task entry是否取消了timer task
def cancelled: Boolean = {
timerTask.getTimerTaskEntry != this
}
def remove(): Unit = {
var currentList = list
// remove 被调用,其他的线程将会移动这个entry到一个其他的TimeTaskList,因此我们会重试直到TimeTaskList为空
// 删除这个entry可能会失败,因为TimeTaskList的值的改变
while (currentList != null) {
// 从TimerTaskLKList删除指定的TimerTaskEntry
currentList.remove(this)
// TimerTaskLKList重新赋给currentList
currentList = list
}
}
override def compare(that: TimerTaskEntry): Int = {
this.expirationMs compare that.expirationMs
}
}
四 TimerTask分析
trait TimerTask extends Runnable {
val delayMs: Long // timestamp in millisecond
private[this] var timerTaskEntry: TimerTaskEntry = null
def cancel(): Unit = {
synchronized {
if (timerTaskEntry != null) timerTaskEntry.remove()
timerTaskEntry = null
}
}
// 即某一个timer task entry希望持有这个timer task,但是其他的timer task正持有它,则就把当前的这个timer task entry给删掉
private[timer] def setTimerTaskEntry(entry: TimerTaskEntry): Unit = {
synchronized {
// 如果某一个timer task被已经存在的timer task entry所持有,我们首先会删除这个timer task entry
if (timerTaskEntry != null && timerTaskEntry != entry)
timerTaskEntry.remove()
timerTaskEntry = entry
}
}
private[timer] def getTimerTaskEntry(): TimerTaskEntry = {
timerTaskEntry
}
}