Guava是Java领域优秀的开源项目,它包含了Google在Java项目中使用一些核心库,提供了令牌桶算法实现
平滑突发限流
使用 RateLimiter的静态方法创建一个限流器,设置每秒放置的令牌数为5个。返回的RateLimiter对象可以保证1秒内不会给超过5个令牌,并且以固定速率进行放置,达到平滑输出的效果。
public static void testSmoothBursty2() throws InterruptedException {
//1s创建2个令牌
RateLimiter r = RateLimiter.create(2);
while (true)
{
System.out.println("get 1 tokens: " + r.acquire(1) + "s");
//1s产生2个,1.5s产生3个所以后面3个不用等待,第4个需要等待0.5s
Thread.sleep(1500);
System.out.println("get 1 tokens: " + r.acquire(1) + "s");
System.out.println("get 1 tokens: " + r.acquire(1) + "s");
System.out.println("get 1 tokens: " + r.acquire(1) + "s");
System.out.println("get 1 tokens: " + r.acquire(1) + "s");
System.out.println("end");
/**
output:
get 1 tokens: 0.0s
get 1 tokens: 0.0s
get 1 tokens: 0.0s
get 1 tokens: 0.0s
get 1 tokens: 0.499795s
end
get 1 tokens: 0.497932s
get 1 tokens: 0.0s
get 1 tokens: 0.0s
get 1 tokens: 0.0s
get 1 tokens: 0.499886s
end
get 1 tokens: 0.499646s
get 1 tokens: 0.0s
get 1 tokens: 0.0s
get 1 tokens: 0.0s
get 1 tokens: 0.499825s
end
*/
}
}
平滑预热限流
RateLimiter的 SmoothWarmingUp是带有预热期的平滑限流,它启动后会有一段预热期,逐步将分发频率提升到配置的速率。 比如下面代码中的例子,创建一个平均分发令牌速率为2,预热期为3分钟。由于设置了预热时间是3秒,令牌桶一开始并不会0.5秒发一个令牌,而是形成一个平滑线性下降的坡度,频率越来越高,在3秒钟之内达到原本设置的频率,以后就以固定的频率输出。这种功能适合系统刚启动需要一点时间来“热身”的场景。
public void testSmoothwarmingUp() {
RateLimiter r = RateLimiter.create(2, 3, TimeUnit.SECONDS);
while (true)
{
System.out.println("get 1 tokens: " + r.acquire(1) + "s");
System.out.println("get 1 tokens: " + r.acquire(1) + "s");
System.out.println("get 1 tokens: " + r.acquire(1) + "s");
System.out.println("get 1 tokens: " + r.acquire(1) + "s");
System.out.println("end");
/**
* output:
* get 1 tokens: 0.0s
* get 1 tokens: 1.329289s
* get 1 tokens: 0.994375s
* get 1 tokens: 0.662888s 上边三次获取的时间相加正好为3秒
* end
* get 1 tokens: 0.49764s 正常速率0.5秒一个令牌
* get 1 tokens: 0.497828s
* get 1 tokens: 0.49449s
* get 1 tokens: 0.497522s
*/
}
}