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