dubbo源码:HashedWheelTimer解析

文章目录

1.概要

旧的dubbo使用了Executors.newScheduledThreadPool来进行定时重试,新的提交在2018-12-11号使用了HashedWheelTimer,其原理不再解释,直接分析dubbo中的HashedWheelTimer类,如下:

  • 时间轮由 HashedWheelBucket 数组构成,每个 HashedWheelBucket 维持一个双链表,双链表中的元素是HashedWheelTimeout类型

  • HashedWheelTimeout 包含TimerTask、deadline等属性

  • HashedWheelTimer只有一个工作线程,即Worker线程,worker开启后在当前tick内执行当前bucket中的task

    HashedWheelTimeout也是根据tick加入到对应的bucket的,所以执行当前的tick时会执行所有符合条件的(remainingRounds=0,大于0的话需要等待对应的tick到达才可以执行,每执行一次remainingRounds减一)

  • HashedWheelTimer的使用方式:

    // Step 1:创建hashedWheelTimer实例
    HashedWheelTimer hashedWheelTimer = new HashedWheelTimer(new NamedThreadFactory("DubboRegistryRetryTimer", true), retryPeriod, TimeUnit.MILLISECONDS, 128);
    
    // Step 2:创建TimerTask,以dubbo源码中的FailedRegisteredTask为例
    TimerTask task = new FailedRegisteredTask(url, this);
    
    // Step 3:创建HashedWheelTimeout,即添加超时任务,并开启时间轮线程
    hashedWheelTimer.newTimeout(task, 5000, TimeUnit.MILLISECONDS);
    

2源码分析

public class HashedWheelTimer implements Timer {
  
  public static final String NAME = "hased";
  
  private static final AtomicInteger INSTANCE_COUNTER = new AtomicInteger();
  
  private static final AtomicBoolean WARNED_TOO_MANY_INSTANCES = new AtomicBoolean();
  
  private static final int INSTANCE_COUNT_LIMIT = 64;
  
  private static final AtomicIntegerFieldUpdater<HashedWheelTimer> WORKER_STATE_UPDATER =
            AtomicIntegerFieldUpdater.newUpdater(HashedWheelTimer.class, "workerState");
  
  
  private final Worker worker = new Worker();
  
  private final Thread workerThread;
  
  private static final int WORKER_STATE_INIT = 0; // 0-初始化
  private static final int WORKER_STATE_STARTED = 1; // 1-已启动
  private static final int WORKER_STATE_SHUTDOWN = 2; // 2-关闭
  
  private volatile int workerState;
  
  private final long tickDuration; // 每次tick的持续时长
  private final HashedWheelBucket[] wheel;
  private final int mask;
  private final CountDownLatch startTimeInitialized = new CountDownLatch(1);
  private final Queue<HashedWheelTimeout> timeouts = new LinkedBlockingQueue<>();
  private final Queue<HashedWheelTimeout> cancelledTimeouts = new LinkedBlockingQueue<>();
  private final AtomicLong pendingTimeouts = new AtomicLong(0);
  private final long maxPendingTimeouts;
  
  private volatile long startTime;
  
  // 构造函数省略......

  /**
  ** 创建Wheel
  **/
  private static HashedWheelBucket[] createWheel(int ticksPerWheel) {
    // 省略ticksPerWheel验证信息
    
    // 获取标准化的wheel的大小
    ticksPerWheel = normalizeTicksPerWheel(ticksPerWheel);
    
    HashedWheelBucket[] wheel = new HashedWheelBucket[ticksPerWheel];
    for (int i = 0; i < wheel.length; i++) {
      // 依次创建wheel中的每个bucket
      wheel[i] = new HashedWheelBucket();
    }
    return wheel;
  }
  
  /**
  ** 标准化wheel的大小,比如9,则标准化为16,17则标准化为32,34则标准化为64
  **/
  private static int normalizeTicksPerWheel(int ticksPerWheel) {
    int normalizedTicksPerWheel = ticksPerWheel - 1;
    normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 1;
    normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 2;
    normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 4;
    normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 8;
    normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 16;
    return normalizedTicksPerWheel + 1;
  }
  
  public void start() {
    switch (WORKER_STATE_UPDATER.get(this)) {
      case WORKER_STATE_INIT:
      if (WORKER_STATE_UPDATER.compareAndSet(this,WORKER_STATE_INIT,WORKER_STATE_STARTED)) {
        // 
        workerThread.start();
      }
        break;
      // 省略其他case
    }

    // Wait until the startTime is initialized by the worker.
    while (startTime == 0) {
      startTimeInitialized.await();
    }
  }
  
  // 中断 tick 线程,即本类中的workerThread线程
  @Override
  public Set<Timeout> stop() {
    if (Thread.currentThread() == workerThread) {
      // 抛出异常:stop方法不能被取消
    }
    
    if (!WORKER_STATE_UPDATER.compareAndSet(this, WORKER_STATE_STARTED, WORKER_STATE_SHUTDOWN)) {
      if (WORKER_STATE_UPDATER.getAndSet(this, WORKER_STATE_SHUTDOWN) != WORKER_STATE_SHUTDOWN) {
        INSTANCE_COUNTER.decrementAndGet();
      }
      return Collections.emptySet();
    }
    
    try {
      boolean interrupted = false;
      while (workerThread.isAlive()) {
        workerThread.interrupt();
        try {
          workerThread.join(100);
        } catch (InterruptedException ignored) {
          interrupted = true;
        }
      }
      
      if (interrupted) {
        Thread.currentThread().interrupt();
      }
    } finally {
      INSTANCE_COUNTER.decrementAndGet();
    }
    return worker.unprocessedTimeouts();
  }
  
  @Override
  public boolean isStop() {
    return WORKER_STATE_SHUTDOWN == WORKER_STATE_UPDATER.get(this);
  }
  
  @Override
  public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) {
    // 省略task和unit校验
    long pendingTimeoutsCount = pendingTimeouts.incrementAndGet(); // 等待的timeout加1
    
    if (maxPendingTimeouts > 0 && pendingTimeoutsCount > maxPendingTimeouts) {
      pendingTimeouts.decrementAndGet();
      // 抛出异常返回:等待处理的超时任务超过最大值
    }
    
    start(); // 开启时间轮线程,即workerThread线程

    // deadline = 当前时间 + 任务延迟 - timer启动时间,即timer启动到任务结束的时间
    long deadline = System.nanoTime() + unit.toNanos(delay) - startTime;
    
    // 校验
    if (delay > 0 && deadline < 0) {
      deadline = Long.MAX_VALUE;
    }
    
    // 新建timeout,并加入到线程安全的链式队列 timeouts 中
    HashedWheelTimeout timeout = new HashedWheelTimeout(this, task, deadline);
    timeouts.add(timeout);
    return timeout;
  }

  /**
   * 返回当前Timer中pending timeouts的数量
   */
  public long pendingTimeouts() {
    return pendingTimeouts.get();
  }
  
  /**
  ** 工作线程
  **/
  private final class Worker implements Runnable {
    // 未处理的timeout set集合
    private final Set<Timeout> unprocessedTimeouts = new HashSet<Timeout>();
    
    private long tick; // 当前已经tick的次数
    
    @Override
    public void run() {
      startTime = System.nanoTime();
      // 我们使用0作为未初始化的值,确定startTime若初始化即不可能为0
      if (startTime == 0) {
        startTime = 1;
      }

      // Notify the other threads waiting for the initialization at start().
      startTimeInitialized.countDown();
      
      do {
        final long deadline = waitForNextTick(); // 等到当前tick的时间
        if (deadline > 0) {
          int idx = (int) (tick & mask); // 获取bucket的索引
          processCancelledTasks(); 
          HashedWheelBucket bucket = wheel[idx]; // 获取bucket
          transferTimeoutsToBuckets(); // 需要加入bucket的timeout加入
          bucket.expireTimeouts(deadline); // 遍历当前的bucket,执行完、已经取消的从链表中移除
          tick++;
        }
      } while (WORKER_STATE_UPDATER.get(HashedWheelTimer.this) == WORKER_STATE_STARTED);
      
      // Fill the unprocessedTimeouts so we can return them from stop() method.
      for (HashedWheelBucket bucket : wheel) {
        bucket.clearTimeouts(unprocessedTimeouts);
      }
      
      for (; ; ) {
        HashedWheelTimeout timeout = timeouts.poll();
        if (timeout == null) {
          break;
        }
        if (!timeout.isCancelled()) {
          unprocessedTimeouts.add(timeout);
        }
      }
      processCancelledTasks();
    }

    
    private void transferTimeoutsToBuckets() {
      for (int i = 0; i < 100000; i++) {
        HashedWheelTimeout timeout = timeouts.poll();
        if (timeout == null) {
          // 所有的都已经处理过了
          break;
        }
        
        if (timeout.state() == HashedWheelTimeout.ST_CANCELLED) {
          continue;
        }
        // calculated表示当前timeout需要tick的次数
        long calculated = timeout.deadline / tickDuration;
        // remainingRounds表示当前timeout剩余的轮数
        timeout.remainingRounds = (calculated - tick) / wheel.length;
        
        final long ticks = Math.max(calculated, tick); 
        int stopIndex = (int) (ticks & mask); // 当前任务应该插入的bucket索引
        HashedWheelBucket bucket = wheel[stopIndex]; 
        bucket.addTimeout(timeout); // 插入到对应的bucket中
      }
    }
    
    // 处理取消的timeout
    private void processCancelledTasks() {
      for (; ; ) {
        HashedWheelTimeout timeout = cancelledTimeouts.poll();
        if (timeout == null) {
          // 所有的都已经处理过了
          break;
        }
        timeout.remove();
      }
    }
    
    /**
    ** 根据 startTime 和当前 tick 的次数计算目标nanoTime,然后等到目标nanoTime为止
    **/
    private long waitForNextTick() {
      long deadline = tickDuration * (tick + 1);
      for (; ; ) {
        final long currentTime = System.nanoTime() - startTime;
        // 需要睡眠的时间
        long sleepTimeMs = (deadline - currentTime + 999999) / 1000000;
        
        if (sleepTimeMs <= 0) {
          if (currentTime == Long.MIN_VALUE) {
            return -Long.MAX_VALUE;
          } else {
            return currentTime;
          }
        }
        
        // 当前环境是windows环境
        if (isWindows()) {
          sleepTimeMs = sleepTimeMs / 10 * 10;
        }
        
        try {
          // 睡眠sleepTimeMs
          Thread.sleep(sleepTimeMs);
        } catch (InterruptedException ignored) {
          // 如果收到shutdown请求返回Long.MIN_VALUE
          if (WORKER_STATE_UPDATER.get(HashedWheelTimer.this) == WORKER_STATE_SHUTDOWN) {
            return Long.MIN_VALUE;
          }
        } // try
      }
    }
    
    Set<Timeout> unprocessedTimeouts() {
      return Collections.unmodifiableSet(unprocessedTimeouts);
    }
  }
  
  
  private static final class HashedWheelTimeout implements Timeout {
    
    private static final int ST_INIT = 0;
    private static final int ST_CANCELLED = 1;
    private static final int ST_EXPIRED = 2;
    
    private static final AtomicIntegerFieldUpdater<HashedWheelTimeout> STATE_UPDATER =
                AtomicIntegerFieldUpdater.newUpdater(HashedWheelTimeout.class, "state");
    
    private final HashedWheelTimer timer;
    private final TimerTask task;
    private final long deadline;
    
    private volatile int state = ST_INIT;
    
    // 计算剩余的轮数, 只有timer走够轮数, 并且到达了task所在的slot, task 才会过期
    long remainingRounds;
    
    HashedWheelTimeout next;
    HashedWheelTimeout prev;
    
    // 当前timeout所有的bucket
    HashedWheelBucket bucket;
    
    HashedWheelTimeout(HashedWheelTimer timer, TimerTask task, long deadline) {
      this.timer = timer;
      this.task = task;
      this.deadline = deadline;
    }
    
    @Override
    public Timer timer() {
      return timer;
    }
    
    @Override
    public TimerTask task() {
      return task;
    }
    
    /**
    ** 把当前的timeout设置为已取消
    **/
    @Override
    public boolean cancel() {
      // only update the state it will be removed from HashedWheelBucket on next tick.
      if (!compareAndSetState(ST_INIT, ST_CANCELLED)) {
        return false;
      }
      timer.cancelledTimeouts.add(this);
      return true;
    }

    void remove() {
      HashedWheelBucket bucket = this.bucket;
      if (bucket != null) {
        // 从当前bucket移除
        bucket.remove(this);
      } else {
        timer.pendingTimeouts.decrementAndGet();
      }
    }
    
    public boolean compareAndSetState(int expected, int state) {
      return STATE_UPDATER.compareAndSet(this, expected, state);
    }

    public int state() {
      return state;
    }
    
    // 当前timeout是否已取消
    @Override
    public boolean isCancelled() {
      return state() == ST_CANCELLED;
    }
    
    // 当前timeout是否已过期
    @Override
    public boolean isExpired() {
      return state() == ST_EXPIRED;
    }
    
    public void expire() {
      // 先设置当前timeout的状态为已过期状态
      if (!compareAndSetState(ST_INIT, ST_EXPIRED)) {
        return;
      }
      task.run(this);
    }
    
    // 省略toString方法
  }

  
  
  
  private static final class HashedWheelBucket {
    private HashedWheelTimeout head; // 头结点
    private HashedWheelTimeout tail; // 尾结点
    
    /**
    ** 将新的timeout插入链表的尾部,
    **/
    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;
      }
    }

    
    /**
    ** 遍历当前的bucket,执行完、已经取消的从链表中移除
    **/
    void expireTimeouts(long deadline) {
      HashedWheelTimeout timeout = head;
      
      while (timeout != null) {
        HashedWheelTimeout next = timeout.next;
        if (timeout.remainingRounds <= 0) {
          // timer走够了轮数,并且到达该bucket,则移除timeout
          next = remove(timeout);
          if (timeout.deadline <= deadline) {
            // 过期
            timeout.expire();
          } else {
            // 异常,timeout放错了bucket,不可能发生的情况
          }
        } else if (timeout.isCancelled()) {
          // timeout已经取消了,移除
          next = remove(timeout);
        } else {
          timeout.remainingRounds--;
        }
        // timeout指向下一个
        timeout = next;
      }
    }
    
    
    public HashedWheelTimeout remove(HashedWheelTimeout timeout) {
      HashedWheelTimeout next = timeout.next;
      
      // 断开timeout的prev,同时使用timeout的prev指向timeout的next
      if (timeout.prev != null) {
        timeout.prev.next = next;
      }
      
      // 断开timeout的next,同时使用timeout.next的prev指向timeout的prev
      if (timeout.next != null) {
        timeout.next.prev = timeout.prev;
      }
      
      // timeout是head的情况下,特殊处理
      if (timeout == head) {
        if (timeout == tail) {
          tail = null;
          head = null;
        } else {
          head = next;
        }
      } else if (timeout == tail) {
        tail = timeout.prev;
      }
      
      timeout.prev = null;
      timeout.next = null;
      timeout.bucket = null;
      // 当前等待的timeout减一,即HashedWheelTimer中的pendingTimeouts属性减一
      timeout.timer.pendingTimeouts.decrementAndGet();
      return next;
    }

    /**
    * 清空bucket,并返回不是过期/取消的Timeout
    */
    void clearTimeouts(Set<Timeout> set) {
      for (; ; ) {
        HashedWheelTimeout timeout = pollTimeout();
        if (timeout == null) {
          return;
        }
        if (timeout.isExpired() || timeout.isCancelled()) {
          continue;
        }
        set.add(timeout);
      }
    }

    // 清空bucket
    private HashedWheelTimeout pollTimeout() {
      HashedWheelTimeout head = this.head;
      if (head == null) {
        return null;
      }
      HashedWheelTimeout next = head.next;
      if (next == null) {
        tail = this.head = null;
      } else {
        this.head = next;
        next.prev = null;
      }
      
      head.next = null;
      head.prev = null;
      head.bucket = null;
      return head;
    }
    
  } // HashedWheelBucket结束
  
  //......
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bboyzqh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值