RateLimiter 源码分析

RateLimiter为guava包下以令牌桶算法抽出来的基类。

在这里要说明一下,在令牌桶算法中,理论上是要每隔一定的时间往桶里添加令牌,具体的实现方式有两种
第一种:常规实现是采用定时任务,每隔一定的时间往桶里添加令牌 ,该种方式需要额外开启后台线程,消耗资源
第二种:(补偿思路) 保存下一次需要添加令牌的时间nextFreeTicketMicros,每次请求时,进行补偿(核对当前时间是否超过nextFreeTicketMicros,如果超过则补偿期间缺少的令牌)  
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.google.common.util.concurrent;

import com.google.common.annotations.Beta;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.SmoothRateLimiter.SmoothBursty;
import com.google.common.util.concurrent.SmoothRateLimiter.SmoothWarmingUp;
import java.util.concurrent.TimeUnit;
import javax.annotation.concurrent.ThreadSafe;

@ThreadSafe
@Beta
public abstract class RateLimiter {
    private final RateLimiter.SleepingStopwatch stopwatch;
    private volatile Object mutexDoNotUseDirectly;

  //创建一个RateLimiter
    public static RateLimiter create(double permitsPerSecond) {
        return create(RateLimiter.SleepingStopwatch.createFromSystemTimer(), permitsPerSecond);
    }

    @VisibleForTesting
    static RateLimiter create(RateLimiter.SleepingStopwatch stopwatch, double permitsPerSecond) {
        RateLimiter rateLimiter = new SmoothBursty(stopwatch, 1.0D);
        rateLimiter.setRate(permitsPerSecond);//设置速率,
        return rateLimiter;
    }

    public static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit) {
        Preconditions.checkArgument(warmupPeriod >= 0L, "warmupPeriod must not be negative: %s", new Object[]{Long.valueOf(warmupPeriod)});
        return create(RateLimiter.SleepingStopwatch.createFromSystemTimer(), permitsPerSecond, warmupPeriod, unit);
    }

    @VisibleForTesting
    static RateLimiter create(RateLimiter.SleepingStopwatch stopwatch, double permitsPerSecond, long warmupPeriod, TimeUnit unit) {
        RateLimiter rateLimiter = new SmoothWarmingUp(stopwatch, warmupPeriod, unit);
        rateLimiter.setRate(permitsPerSecond);
        return rateLimiter;
    }

    private Object mutex() { //锁,单例锁
        Object mutex = this.mutexDoNotUseDirectly;
        if(mutex == null) {
            synchronized(this) {
                mutex = this.mutexDoNotUseDirectly;
                if(mutex == null) {
                    this.mutexDoNotUseDirectly = mutex = new Object();
                }
            }
        }

        return mutex;
    }

    RateLimiter(RateLimiter.SleepingStopwatch stopwatch) { //核对stopwatch是否为空
        this.stopwatch = (RateLimiter.SleepingStopwatch)Preconditions.checkNotNull(stopwatch);
    }

    public final void setRate(double permitsPerSecond) { //设置速度
       //速度必须为正数
        Preconditions.checkArgument(permitsPerSecond > 0.0D && !Double.isNaN(permitsPerSecond), "rate must be positive");
  //加锁设计速度
        synchronized(this.mutex()) {
            this.doSetRate(permitsPerSecond, this.stopwatch.readMicros());
        }
    }

    abstract void doSetRate(double var1, long var3);
   //获取速度
    public final double getRate() {
        synchronized(this.mutex()) {
            return this.doGetRate();
        }
    }

    abstract double doGetRate();

    public double acquire() {
        return this.acquire(1);
    }

    public double acquire(int permits) {
        long microsToWait = this.reserve(permits); //等待时间
        this.stopwatch.sleepMicrosUninterruptibly(microsToWait); //当前线程等待microsToWait时间
        return 1.0D * (double)microsToWait / (double)TimeUnit.SECONDS.toMicros(1L);
    }

    final long reserve(int permits) {
        checkPermits(permits);
        synchronized(this.mutex()) {
            return this.reserveAndGetWaitLength(permits, this.stopwatch.readMicros()); //获取等待的时间
        }
    }

    public boolean tryAcquire(long timeout, TimeUnit unit) {
        return this.tryAcquire(1, timeout, unit);
    }

    public boolean tryAcquire(int permits) {
        return this.tryAcquire(permits, 0L, TimeUnit.MICROSECONDS);
    }

    public boolean tryAcquire() {
        return this.tryAcquire(1, 0L, TimeUnit.MICROSECONDS);
    }

    public boolean tryAcquire(int permits, long timeout, TimeUnit unit) {
        long timeoutMicros = Math.max(unit.toMicros(timeout), 0L);
        checkPermits(permits);
        long microsToWait;
        synchronized(this.mutex()) {
            long nowMicros = this.stopwatch.readMicros();
            if(!this.canAcquire(nowMicros, timeoutMicros)) {
                return false;
            }

            microsToWait = this.reserveAndGetWaitLength(permits, nowMicros);
        }

        this.stopwatch.sleepMicrosUninterruptibly(microsToWait);
        return true;
    }

    private boolean canAcquire(long nowMicros, long timeoutMicros) {
        return this.queryEarliestAvailable(nowMicros) - timeoutMicros <= nowMicros;
    }

    final long reserveAndGetWaitLength(int permits, long nowMicros) {

        long momentAvailable = this.reserveEarliestAvailable(permits, nowMicros);
       //momnetAvilable为返回下一次应该添加的时间
        return Math.max(momentAvailable - nowMicros, 0L); //返回时差,取最大值,也就是等待时间
    }

    abstract long queryEarliestAvailable(long var1);
     //子类实现
    abstract long reserveEarliestAvailable(int var1, long var2);

    public String toString() {
        return String.format("RateLimiter[stableRate=%3.1fqps]", new Object[]{Double.valueOf(this.getRate())});
    }

    private static int checkPermits(int permits) {
        Preconditions.checkArgument(permits > 0, "Requested permits (%s) must be positive", new Object[]{Integer.valueOf(permits)});
        return permits;
    }

    //SleepingStopwatch 该类的主要作用是,控制请求线程是否应该睡眠
    @VisibleForTesting
    abstract static class SleepingStopwatch {
        SleepingStopwatch() {
        }

        abstract long readMicros();

        abstract void sleepMicrosUninterruptibly(long var1);

        static final RateLimiter.SleepingStopwatch createFromSystemTimer() {
            return new RateLimiter.SleepingStopwatch() {
                final Stopwatch stopwatch = Stopwatch.createStarted();
              //读取当前的系统时间
                long readMicros() {
                    return this.stopwatch.elapsed(TimeUnit.MICROSECONDS);
                }
              //不可中断的睡眠当前线程
                void sleepMicrosUninterruptibly(long micros) {
                    if(micros > 0L) {
                        Uninterruptibles.sleepUninterruptibly(micros, TimeUnit.MICROSECONDS);
                    }

                }
            };
        }
    }
}

 

 

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.google.common.util.concurrent;

import com.google.common.util.concurrent.RateLimiter.SleepingStopwatch;
import java.util.concurrent.TimeUnit;

abstract class SmoothRateLimiter extends RateLimiter {
    double storedPermits;
    double maxPermits;
    double stableIntervalMicros;
    private long nextFreeTicketMicros;

    private SmoothRateLimiter(SleepingStopwatch stopwatch) {
        super(stopwatch);
        this.nextFreeTicketMicros = 0L; //设置下一次获取的时间
    }

    final void doSetRate(double permitsPerSecond, long nowMicros) { //设置请求的速度
        this.resync(nowMicros);
        double stableIntervalMicros = (double)TimeUnit.SECONDS.toMicros(1L) / permitsPerSecond;
        this.stableIntervalMicros = stableIntervalMicros;
        this.doSetRate(permitsPerSecond, stableIntervalMicros);//调用重载方法
    }

    abstract void doSetRate(double var1, double var3);

    final double doGetRate() {
        return (double)TimeUnit.SECONDS.toMicros(1L) / this.stableIntervalMicros;
    }

    final long queryEarliestAvailable(long nowMicros) {
        return this.nextFreeTicketMicros;
    }
   //RateLimiter的中reserverEarliestAvilable的具体实现
   //该方法是精髓,该方法在同步块中操作,每次只有一个线程能够进行操作(注意,同步快中时睡眠,而不是wait即不会释放锁),
   //该方法的设计逻辑主要是应用在如下场景中,某一段时间内,申请大量令牌,令牌数,超过本地剩余的令牌数,系统会超前支付
  //一定的令牌数,并调整下次产生令牌的时间,当再有线程申请时,若没到时间将会进入睡眠以等待令牌产生,并计算此次超前
  //支付的数量更新nextFreeTickMicros(即时间请求到来的紧凑,每次线程都睡眠等待,会一直超前支付,具体可自行假设多个线程请求令牌即可,因为线程睡眠前会调用reserveEarliestAvailable,又会重新计算nextFreeTicketMicros,当有线程来时会与新的nextFreeTicketMicros比较)
    final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {
        this.resync(nowMicros);//重新刷新令牌数
        long returnValue = this.nextFreeTicketMicros;//返回nextFreeTicketMicros
        double storedPermitsToSpend = Math.min((double)requiredPermits, this.storedPermits);
        double freshPermits = (double)requiredPermits - storedPermitsToSpend;
        long waitMicros = this.storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend) + (long)(freshPermits * this.stableIntervalMicros);
        //为什么要加waitMicros,因为会突然涌入大量请求,而现有令牌数又不够用,因此会预先支付一定的令牌数,
       //waitMicros即是产生预先支付令牌的数量时间,则将下次要添加令牌的时间应该计算时间+watiMicros
        this.nextFreeTicketMicros += waitMicros; 
        this.storedPermits -= storedPermitsToSpend;//更新令牌数,最低数量为0
        return returnValue;
    }

    abstract long storedPermitsToWaitTime(double var1, double var3);//实现中直接返回0

   //刷新令牌数,并重新设置nextFreeTIcketMicros(下次提取时间线)
    private void resync(long nowMicros) {
        if(nowMicros > this.nextFreeTicketMicros) 
            this.storedPermits = Math.min(this.maxPermits, this.storedPermits + (double)(nowMicros - 
 //stableIntervalMicros为 产生一个令牌所需要的时间
this.nextFreeTicketMicros) / this.stableIntervalMicros);
            this.nextFreeTicketMicros = nowMicros;
        }

    }

    static final class SmoothBursty extends SmoothRateLimiter {
        final double maxBurstSeconds;

        SmoothBursty(SleepingStopwatch stopwatch, double maxBurstSeconds) {
            super(stopwatch, (SmoothRateLimiter.SyntheticClass_1)null);
            this.maxBurstSeconds = maxBurstSeconds;
        }

        void doSetRate(double permitsPerSecond, double stableIntervalMicros) {
            double oldMaxPermits = this.maxPermits;
            this.maxPermits = this.maxBurstSeconds * permitsPerSecond;
            if(oldMaxPermits == 1.0D / 0.0) {
                this.storedPermits = this.maxPermits;
            } else {
                this.storedPermits = oldMaxPermits == 0.0D?0.0D:this.storedPermits * this.maxPermits / oldMaxPermits;
            }

        }

        long storedPermitsToWaitTime(double storedPermits, double permitsToTake) {
            return 0L;
        }
    }

    static final class SmoothWarmingUp extends SmoothRateLimiter {
        private final long warmupPeriodMicros;
        private double slope;
        private double halfPermits;

        SmoothWarmingUp(SleepingStopwatch stopwatch, long warmupPeriod, TimeUnit timeUnit) {
            super(stopwatch, (SmoothRateLimiter.SyntheticClass_1)null);
            this.warmupPeriodMicros = timeUnit.toMicros(warmupPeriod);
        }

        void doSetRate(double permitsPerSecond, double stableIntervalMicros) {
            double oldMaxPermits = this.maxPermits;
            this.maxPermits = (double)this.warmupPeriodMicros / stableIntervalMicros;
            this.halfPermits = this.maxPermits / 2.0D;
            double coldIntervalMicros = stableIntervalMicros * 3.0D;
            this.slope = (coldIntervalMicros - stableIntervalMicros) / this.halfPermits;
            if(oldMaxPermits == 1.0D / 0.0) {
                this.storedPermits = 0.0D;
            } else {
                this.storedPermits = oldMaxPermits == 0.0D?this.maxPermits:this.storedPermits * this.maxPermits / oldMaxPermits;
            }

        }

        long storedPermitsToWaitTime(double storedPermits, double permitsToTake) {
            double availablePermitsAboveHalf = storedPermits - this.halfPermits;
            long micros = 0L;
            if(availablePermitsAboveHalf > 0.0D) {
                double permitsAboveHalfToTake = Math.min(availablePermitsAboveHalf, permitsToTake);
                micros = (long)(permitsAboveHalfToTake * (this.permitsToTime(availablePermitsAboveHalf) + this.permitsToTime(availablePermitsAboveHalf - permitsAboveHalfToTake)) / 2.0D);
                permitsToTake -= permitsAboveHalfToTake;
            }

            micros = (long)((double)micros + this.stableIntervalMicros * permitsToTake);
            return micros;
        }

        private double permitsToTime(double permits) {
            return this.stableIntervalMicros + permits * this.slope;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值