Google Guava提供的RateLimiter
使用的是令牌桶算法。令牌桶算法的基本思想是以固定的速率生成令牌,在执行请求之前都需要从令牌桶里获取足够的令牌。当令牌数量不足的时候,请求将被阻塞进入等待状态或者直接返回失败。RateLimiter
常用于限制访问资源的速率。
RateLimiter使用示例
下面是一个RateLimiter的简单使用示例:
1 | public class RateLimiterTest { |
我们定义了一个RateLimiter
实例,每秒钟产生0.5张令牌,即每2秒钟产生1张令牌。testLimiter
方法中通过limiter.acquire()
方法获取令牌(不带参数时默认获取1张令牌)。Executors.newFixedThreadPool(5)
生成五个线程,并发调用testLimiter
方法,执行代码,控制台输出如下所示:
1 | Thread[pool-1-thread-1,5,main] waiting 0.0 |
可以看到每个线程调用时间相隔大约为2秒钟。可能你会问,为什么第一个线程没有等待2秒,直接就获取到了令牌然后执行了呢?
Guava RateLimiter允许某次请求获取超出剩余令牌数的令牌,但是下一次请求将为此付出代价,一直等到令牌亏空补上。再来看一个RateLimiter
的例子:
1 | public class RateLimiterTest { |
程序输出如下:
1 | 0.0 |
上面例子钟,一秒钟产生一张令牌,第一次请求直接取出4张令牌,所以第二次请求需要等待4/1秒才能取到令牌。经过大约4秒后,第二次请求直接取出3张令牌,所以第三次请求需要等待3/1秒后才能取到令牌,依此类推。
设置超时时间
我们可以设置等待令牌的超时时间,如果等待令牌的时间大于超时时间,将直接返回false,不再等待:
1 | public class RateLimiterTest { |
上面例子limiter.tryAcquire
设置了超时时间为2秒,由于第一次请求一次性获取了3张令牌,所以这里需要等待大约3秒钟,超出了2秒的超时时间,所以limiter.tryAcquire
不会等待3秒,而是直接返回false。