HashedWheelTimer源码学习

原创
2020/09/10 18:01
阅读数 71

基本概念

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;
    }
}

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部