当前位置:   article > 正文

你说这是冷知识?Netty时间轮调度算法原理分析,蚂蚁金服面试Java后端经历_reporttimer.java

reporttimer.java
    }

    // 创建工作线程
    workerThread = threadFactory.newThread(worker);

    // 非守护线程且 leakDetection 为 true 时检测内存是否泄漏
    leak = leakDetection || !workerThread.isDaemon() ? leakDetector.track(this) : null;

    // 初始化最大等待任务数
    this.maxPendingTimeouts = maxPendingTimeouts;

    // 如果创建的时间轮实例大于 64,打印日志,并且这个日志只会打印一次
    if (INSTANCE_COUNTER.incrementAndGet() > INSTANCE_COUNT_LIMIT &&
        WARNED_TOO_MANY_INSTANCES.compareAndSet(false, true)) {
        reportTooManyInstances();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

构造函数中的参数相当重要,当自定义时间轮时,我们应该根据业务的范围设置合理的参数:

*   threadFactory:创建时间轮任务线程的工厂,通过这个工厂可以给我们的线程自定义一些属性(线程名、异常处理等)
*   tickDuration:时钟多长时间拨动一次,值越小,时间轮精度越高
*   unit:`tickDuration` 的单位
*   ticksPerWheel:时间轮数组大小
*   leakDetection:是否检测内存泄漏
*   maxPendingTimeouts:时间轮内最大等待的任务数

时间轮的时钟拨动时长应该根据业务设置恰当的值,如果设置的过大,可能导致任务触发时间不准确。如果设置的过小,时间轮转动频繁,任务少的情况下加载不到任务,属于一直空转的状态,会占用 CPU 线程资源。

为了防止时间轮占用过多的 CPU 资源,当创建的时间轮对象大于 64 时会以日志的方式提示。

构造函数中只是初始化了轮线程,并没有开启,当第一次往时间轮内添加任务时,线程才会开启。

#### 2.3 往时间轮内添加任务

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
@Override
public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) {
    if (task == null) {
        throw new NullPointerException("task");
    }
    if (unit == null) {
        throw new NullPointerException("unit");
    }

    // 等待的任务数 +1
    long pendingTimeoutsCount = pendingTimeouts.incrementAndGet();

    // 如果时间轮内等待的任务数大于最大值,任务会被抛弃
    if (maxPendingTimeouts > 0 && pendingTimeoutsCount > maxPendingTimeouts) {
        pendingTimeouts.decrementAndGet();
        throw new RejectedExecutionException("Number of pending timeouts ("
            + pendingTimeoutsCount + ") is greater than or equal to maximum allowed pending "
            + "timeouts (" + maxPendingTimeouts + ")");
    }

    // 开启时间轮内的线程
    start();

    // 计算当前添加任务的执行时间
    long deadline = System.nanoTime() + unit.toNanos(delay) - startTime;

    // Guard against overflow.
    if (delay > 0 && deadline < 0) {
        deadline = Long.MAX_VALUE;
    }
    // 将任务加入队列
    HashedWheelTimeout timeout = new HashedWheelTimeout(this, task, deadline);
    timeouts.add(timeout);
    return timeout;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

任务会先保存在队列中,当时间轮的时钟拨动时才会判断是否将队列中的任务加载进时间轮。

  • 1
  • 2
  • 3
public void start() {
    switch (WORKER_STATE_UPDATER.get
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/125625
推荐阅读
相关标签
  

闽ICP备14008679号