学习笔记-guava限流源码解读

guava限流源码解读

核心变量

  1. startTick 参考点(限流初始化时间点)
  2. nowMicros 当前时间点(当前时间-参考点)
  3. stableIntervalMicros 生成令牌的速率(每微秒生成令牌数)
  4. maxPermits 可生成的最大令牌数
  5. storedPermits 令牌桶计数器
  6. nextFreeTicketMicros 下次可生成令牌的时间点(可生成令牌的时间点-参考点)
  7. timeoutMicros 获取令牌等待超时时间

核心方法

创建时间计数器


    public static final SleepingStopwatch createFromSystemTimer() {
      return new SleepingStopwatch() {
        final Stopwatch stopwatch = Stopwatch.createStarted();

        @Override
        //获取当前时间基于参考点
        protected long readMicros() {
          return stopwatch.elapsed(MICROSECONDS);
        }

        @Override
        protected void sleepMicrosUninterruptibly(long micros) {
          if (micros > 0) {
            Uninterruptibles.sleepUninterruptibly(micros, MICROSECONDS);
          }
        }
      };
    }

    public static Stopwatch createStarted() {
        return new Stopwatch().start();
    }

    //标记参考点
    public Stopwatch start() {
        checkState(!isRunning, "This stopwatch is already running.");
        isRunning = true;
        startTick = ticker.read();
        return this;
    }

    public long elapsed(TimeUnit desiredUnit) {
        return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
    }

    private long elapsedNanos() {
        return isRunning ? ticker.read() - startTick + elapsedNanos : elapsedNanos;
    }

初始化SmoothBursty限流

    static RateLimiter create(double permitsPerSecond, SleepingStopwatch stopwatch) {
        RateLimiter rateLimiter = new SmoothBursty(stopwatch, 1.0 /* maxBurstSeconds */);
        rateLimiter.setRate(permitsPerSecond);
        return rateLimiter;
    }

    final void doSetRate(double permitsPerSecond, long nowMicros) {
        //初始化令牌桶及下次获取令牌的时间
        resync(nowMicros);
        //计算令牌生成的速率
        double stableIntervalMicros = SECONDS.toMicros(1L) / permitsPerSecond;
        this.stableIntervalMicros = stableIntervalMicros;
        doSetRate(permitsPerSecond, stableIntervalMicros);
    }

    void resync(long nowMicros) {
        // if nextFreeTicket is in the past, resync to now
        if (nowMicros > nextFreeTicketMicros) {
        double newPermits = (nowMicros - nextFreeTicketMicros) / coolDownIntervalMicros();
        storedPermits = min(maxPermits, storedPermits + newPermits);
        nextFreeTicketMicros = nowMicros;
    }

    @Override
    void doSetRate(double permitsPerSecond, double stableIntervalMicros) {
        double oldMaxPermits = this.maxPermits;
        //设置令牌桶容量
        maxPermits = maxBurstSeconds * permitsPerSecond;
        if (oldMaxPermits == Double.POSITIVE_INFINITY) {
        // if we don't special-case this, we would get storedPermits == NaN, below
        storedPermits = maxPermits;
        } else {
            //设置令牌桶存储,令牌桶容量变更后对应比例换算
        storedPermits =
            (oldMaxPermits == 0.0)
                ? 0.0 // initial state
                : storedPermits * maxPermits / oldMaxPermits;
        }
    }

获取令牌

    public boolean tryAcquire(int permits, long timeout, TimeUnit unit) {
        long timeoutMicros = max(unit.toMicros(timeout), 0);
        checkPermits(permits);
        long microsToWait;
        synchronized (mutex()) {
        long nowMicros = stopwatch.readMicros();
        //判断当前时间点是否可以获取令牌
        if (!canAcquire(nowMicros, timeoutMicros)) {
            return false;
        } else {
            //获取令牌并计算超时等待时间
            microsToWait = reserveAndGetWaitLength(permits, nowMicros);
        }
        }
        //超时阻塞等待
        stopwatch.sleepMicrosUninterruptibly(microsToWait);
        return true;
    }

    //判断下次获取令牌的时间是否超过当前时间+超时时间
    private boolean canAcquire(long nowMicros, long timeoutMicros) {
        return queryEarliestAvailable(nowMicros) - timeoutMicros <= nowMicros;
    }

    @Override
    final long queryEarliestAvailable(long nowMicros) {
        return nextFreeTicketMicros;
    }

    @Override
    final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {
        resync(nowMicros);
        long returnValue = nextFreeTicketMicros;
        //令牌桶内令牌
        double storedPermitsToSpend = min(requiredPermits, this.storedPermits);
        //超出令牌桶以外超时部分令牌
        double freshPermits = requiredPermits - storedPermitsToSpend;
        //超时等待时间
        long waitMicros =
            storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
                + (long) (freshPermits * stableIntervalMicros);
        //计算出下次获取令牌的时间
        this.nextFreeTicketMicros = LongMath.saturatedAdd(nextFreeTicketMicros, waitMicros);
        //扣除令牌
        this.storedPermits -= storedPermitsToSpend;
        return returnValue;
    }

注意事项

timeoutMicros 不易设置过大,会阻塞用户线程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值