基本概念
tickDuration: 每 tick 一次的时间间隔
ticksPerWheel : 轮中的 slot 数
remainingRounds: 第几轮 = (calculated - tick) / wheel.length
deadline: 得到过期时间。 long deadline = System.nanoTime() + unit.toNanos(delay) - startTime;
demo例子
HashedWheelTimer hashedWheelTimer = new HashedWheelTimer(Executors.defaultThreadFactory(),1,TimeUnit.SECONDS,64);
hashedWheelTimer.newTimeout(timeout -> {
log.info(String.valueOf(System.currentTimeMillis()));
System.out.println("64定时器执行了");
}, 120, TimeUnit.SECONDS);
hashedWheelTimer.newTimeout(timeout -> {
log.info(String.valueOf(System.currentTimeMillis()));
System.out.println("64定时器执行了");
}, 56, TimeUnit.SECONDS);
HashedWheelTimer 初始化
private static HashedWheelBucket[] createWheel(int ticksPerWheel) {
HashedWheelBucket[] wheel = new HashedWheelBucket[ticksPerWheel];
for (int i = 0; i < wheel.length; i ++) {
wheel[i] = new HashedWheelBucket();
}
return wheel;
}
根据ticksPerWheel的值 ,生成对应的HashedWheelBucket,如例子中给出的是64个槽,则生成64个,如果不是2的平方则自动给出一个最近的值;
HashedWheelBucket数据结构
class HashedWheelBucket {
// Used for the linked-list datastructure
private HashedWheelTimeout head;
private HashedWheelTimeout tail;
/**
* Add {@link HashedWheelTimeout} to this bucket.
*/
public void addTimeout(HashedWheelTimeout timeout) {
assert timeout.bucket == null;
timeout.bucket = this;
if (head == null) {
head = tail = timeout;
} else {
tail.next = timeout;
timeout.prev = tail;
tail = timeout;
}
}
HashedWheelTimeout 数据结构
class HashedWheelTimeout implements Timeout {
private final long deadline;
long remainingRounds; // 轮数
HashedWheelTimeout next;
HashedWheelTimeout prev;
}
程序开始; tick++; 查看是否有新过期任务加入进来;最后检查是否有过期的
do {
final long deadline = waitForNextTick();
if (deadline > 0) {
// 获取当前所对应的槽
int idx = (int) (tick & mask);
processCancelledTasks();
HashedWheelBucket bucket =
wheel[idx];
transferTimeoutsToBuckets();
bucket.expireTimeouts(deadline);
tick++;
}
} while (1);
循环链表找到过期的task;每次进来,轮数小于等于0才过期;否则会把有轮数量的减一。
public void expireTimeouts(long deadline) {
HashedWheelTimeout timeout = head;
// process all timeouts
while (timeout != null) {
HashedWheelTimeout next = timeout.next;
if (timeout.remainingRounds <= 0) {
next = remove(timeout);
if (timeout.deadline <= deadline) {
// 回到用户函数
timeout.expire();
} else {
// The timeout was placed into a wrong slot. This should never happen.
throw new IllegalStateException(String.format(
"timeout.deadline (%d) > deadline (%d)", timeout.deadline, deadline));
}
} else if (timeout.isCancelled()) {
next = remove(timeout);
} else {
timeout.remainingRounds --;
}
timeout = next;
}
}