Guava官方文档-RateLimiter类

原文链接 作者:Dimitris Andreou ?译者:魏嘉鹏 校对:方腾飞token_bucket

RateLimiter 从概念上来讲,速率限制器会在可配置的速率下分配许可证。如果必要的话,每个acquire()?会阻塞当前线程直到许可证可用后获取该许可证。一旦获取到许可证,不需要再释放许可证。

校对注:RateLimiter使用的是一种叫令牌桶的流控算法,RateLimiter会按照一定的频率往桶里扔令牌,线程拿到令牌才能执行,比如你希望自己的应用程序QPS不要超过1000,那么RateLimiter设置1000的速率后,就会每秒往桶里扔1000个令牌。

www.html-guide.com.google.www.html-guide.common.util.concurrent.RateLimiter

@ThreadSafe
@Betapublic
abstract class RateLimiter?extends Object


RateLimiter经常用于限制对一些物理资源或者逻辑资源的访问速率。与Semaphore?相比,Semaphore?限制了并发访问的数量而不是使用速率。(注意尽管并发性和速率是紧密相关的,比如参考Little定律

通过设置许可证的速率来定义RateLimiter。在默认配置下,许可证会在固定的速率下被分配,速率单位是每秒多少个许可证。为了确保维护配置的速率,许可会被平稳地分配,许可之间的延迟会做调整。
可能存在配置一个拥有预热期的RateLimiter?的情况,在这段时间内,每秒分配的许可数会稳定地增长直到达到稳定的速率。

举例来说明如何使用RateLimiter,想象下我们需要处理一个任务列表,但我们不希望每秒的任务提交超过两个:

//速率是每秒两个许可
final RateLimiter rateLimiter = RateLimiter.create(2.0);

void submitTasks(List tasks, Executor executor) {
    for (Runnable task : tasks) {
        rateLimiter.acquire(); // 也许需要等待
        executor.execute(task);
    }
}

再举另外一个例子,想象下我们制造了一个数据流,并希望以每秒5kb的速率处理它??梢酝ü竺扛鲎纸诖硪桓鲂砜?,然后指定每秒5000个许可来完成:

// 每秒5000个许可
final RateLimiter rateLimiter = RateLimiter.create(5000.0); 

void submitPacket(byte[] packet) {
    rateLimiter.acquire(packet.length);
    networkService.send(packet);
}

有一点很重要,那就是请求的许可数从来不会影响到请求本身的限制(调用acquire(1)?和调用acquire(1000)?将得到相同的限制效果,如果存在这样的调用的话),但会影响下一次请求的限制,也就是说,如果一个高开销的任务抵达一个空闲的RateLimiter,它会被马上许可,但是下一个请求会经历额外的限制,从而来偿付高开销任务。注意:RateLimiter?并不提供公平性的保证。

Since:13.0 ?作者: ??Dimitris Andreou

方法摘要

修饰符和类型 方法和描述
double acquire()
从RateLimiter获取一个许可,该方法会被阻塞直到获取到请求
double acquire(int?permits)
从RateLimiter获取指定许可数,该方法会被阻塞直到获取到请求
static?RateLimiter create(double?permitsPerSecond)
根据指定的稳定吞吐率创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少查询)
static?RateLimiter create(double?permitsPerSecond, long?warmupPeriod,?TimeUnit?unit)
根据指定的稳定吞吐率和预热期来创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少个请求量),在这段预热时间内,RateLimiter每秒分配的许可数会平稳地增长直到预热期结束时达到其最大速率。(只要存在足够请求数来使其饱和)
double getRate()
返回RateLimiter?配置中的稳定速率,该速率单位是每秒多少许可数
void setRate(double?permitsPerSecond)
更新RateLimite的稳定速率,参数permitsPerSecond?由构造RateLimiter的工厂方法提供。
String toString()
返回对象的字符表现形式
boolean tryAcquire()
从RateLimiter?获取许可,如果该许可可以在无延迟下的情况下立即获取得到的话
boolean tryAcquire(int?permits)
从RateLimiter?获取许可数,如果该许可数可以在无延迟下的情况下立即获取得到的话
boolean tryAcquire(int?permits, long?timeout,?TimeUnit?unit)
从RateLimiter?获取指定许可数如果该许可数可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可数的话,那么立即返回false?(无需等待)
boolean tryAcquire(long?timeout,?TimeUnit?unit)
从RateLimiter?获取许可如果该许可可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可的话,那么立即返回false(无需等待)
从java.lang.Object 类继承的方法
clone,?equals,?finalize,?getClass,?hashCode,?notify,?notifyAll,?wait,?wait,?wait

方法细节

create
public static?RateLimiter?create(double?permitsPerSecond)
根据指定的稳定吞吐率创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少查询)。
The returned?RateLimiter?ensures that on average no more than?permitsPerSecond?are issued during any given second, with sustained requests being smoothly spread over each second. When the inwww.html-guide.coming request rate exceeds?permitsPerSecond?the rate limiter will release one permit every?(1.0 / permitsPerSecond)?seconds. When the rate limiter is unused, bursts of up to?permitsPerSecond?permits will be allowed, with subsequent requests being smoothly limited at the stable rate of?permitsPerSecond.
返回的RateLimiter?确保了在平均情况下,每秒发布的许可数不会超过permitsPerSecond,每秒钟会持续发送请求。当传入请求速率超过permitsPerSecond,速率限制器会每秒释放一个许可(1.0 / permitsPerSecond 这里是指设定了permitsPerSecond为1.0)?。当速率限制器闲置时,允许许可数暴增到permitsPerSecond,随后的请求会被平滑地限制在稳定速率permitsPerSecond中。
参数:
permitsPerSecond?– 返回的RateLimiter的速率,意味着每秒有多少个许可变成有效。
抛出:
IllegalArgumentException?– 如果permitsPerSecond为负数或者为0
create
public static?RateLimiter?create(double?permitsPerSecond,long?warmupPeriod,TimeUnit?unit)
根据指定的稳定吞吐率和预热期来创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少查询),在这段预热时间内,RateLimiter每秒分配的许可数会平稳地增长直到预热期结束时达到其最大速率(只要存在足够请求数来使其饱和)。同样地,如果RateLimiter?在warmupPeriod时间内闲置不用,它将会逐步地返回冷却状态。也就是说,它会像它第一次被创建般经历同样的预热期。返回的RateLimiter?主要用于那些需要预热期的资源,这些资源实际上满足了请求(比如一个远程服务),而不是在稳定(最大)的速率下可以立即被访问的资源。返回的RateLimiter?在冷却状态下启动(即预热期将会紧跟着发生),并且如果被长期闲置不用,它将回到冷却状态。
参数:

  • permitsPerSecond?– 返回的RateLimiter的速率,意味着每秒有多少个许可变成有效。
  • warmupPeriod?– 在这段时间内RateLimiter会增加它的速率,在抵达它的稳定速率或者最大速率之前
  • unit?– 参数warmupPeriod 的时间单位

抛出:

  • IllegalArgumentException –?如果permitsPerSecond为负数或者为0
setRate
public final?void?setRate(double?permitsPerSecond)
更新RateLimite的稳定速率,参数permitsPerSecond?由构造RateLimiter的工厂方法提供。调用该方法后,当前限制线程不会被唤醒,因此他们不会注意到最新的速率;只有接下来的请求才会。需要注意的是,由于每次请求偿还了(通过等待,如果需要的话)上一次请求的开销,这意味着紧紧跟着的下一个请求不会被最新的速率影响到,在调用了setRate?之后;它会偿还上一次请求的开销,这个开销依赖于之前的速率。RateLimiter的行为在任何方式下都不会被改变,比如如果?RateLimiter?有20秒的预热期配置,在此方法被调用后它还是会进行20秒的预热。
参数:
permitsPerSecond?– RateLimiter的新的稳定速率
抛出:
IllegalArgumentException?– 如果permitsPerSecond为负数或者为0
getRate
public final?double?getRate()
返回RateLimiter?配置中的稳定速率,该速率单位是每秒多少许可数。它的初始值相当于构造这个RateLimiter的工厂方法中的参数permitsPerSecond?,并且只有在调用setRate(double)后才会被更新。
acquire
public?double?acquire()
从RateLimiter获取一个许可,该方法会被阻塞直到获取到请求。如果存在等待的情况的话,告诉调用者获取到该请求所需要的睡眠时间。该方法等同于acquire(1)。
返回:
time spent sleeping to enforce rate, in seconds; 0.0 if not rate-limited
执行速率的所需要的睡眠时间,单位为妙;如果没有则返回0
Since:
16.0 (版本13.0没有返回值)
acquire
public?double?acquire(int?permits)
从RateLimiter获取指定许可数,该方法会被阻塞直到获取到请求数。如果存在等待的情况的话,告诉调用者获取到这些请求数所需要的睡眠时间。
参数:
permits?– 需要获取的许可数
返回:
执行速率的所需要的睡眠时间,单位为妙;如果没有则返回0
抛出:
IllegalArgumentException?– 如果请求的许可数为负数或者为0
Since:
16.0 (版本13.0没有返回值)
tryAcquire
public?boolean?tryAcquire(long?timeout,TimeUnit?unit)
从RateLimiter获取许可如果该许可可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可的话,那么立即返回false(无需等待)。该方法等同于tryAcquire(1, timeout, unit)。
参数:

  • timeout?– 等待许可的最大时间,负数以0处理
  • unit?– 参数timeout 的时间单位

返回:
true表示获取到许可,反之则是false
抛出:
IllegalArgumentException?– 如果请求的许可数为负数或者为0

tryAcquire
public?boolean?tryAcquire(int?permits)
从RateLimiter?获取许可数,如果该许可数可以在无延迟下的情况下立即获取得到的话。该方法等同于tryAcquire(permits, 0, anyUnit)。
参数:
permits?– 需要获取的许可数
返回:
true表示获取到许可,反之则是false
抛出:
IllegalArgumentException?– 如果请求的许可数为负数或者为0
Since:
14.0
tryAcquire
public?boolean?tryAcquire()
从RateLimiter?获取许可,如果该许可可以在无延迟下的情况下立即获取得到的话。
该方法等同于tryAcquire(1)。
返回:
true表示获取到许可,反之则是false
Since:
14.0
tryAcquire
public?boolean?tryAcquire(int?permits,long?timeout,TimeUnit?unit)
从RateLimiter?获取指定许可数如果该许可数可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可数的话,那么立即返回false?(无需等待)。
参数:
permits?– 需要获取的许可数
timeout?– 等待许可数的最大时间,负数以0处理
unit?– 参数timeout 的时间单位
返回:
true表示获取到许可,反之则是false
抛出:
IllegalArgumentException?-如果请求的许可数为负数或者为0
toString
public?String?toString()
以下描述复制于java.lang.Object类。
返回对象的字符表现形式。通常来讲,toString?方法返回一个“文本化呈现”对象的字符串。
结果应该是一个简明但易于读懂的信息表达式。建议所有子类都重写该方法。
toString 方法返回一个由实例的类名,字符’@’和以无符号十六进制表示的对象的哈希值组成的字符串?;痪浠八?,该方法返回的字符串等同于:
getClass().getName() + ‘@’ + Integer.toHexString(hashCode())
重载:
Object类的toString方法
返回:
对象的字符表现形式

原创文章,转载请注明: 转载自九乐棋牌本文链接地址: Guava官方文档-RateLimiter类


FavoriteLoading添加本文到我的收藏
  • Trackback 关闭
  • 评论 (2)
    • 令狐冲
    • 2016/11/13 11:36下午

    我觉得tryAcquire方法的描述应细致一些,如果没有timeout,应该是阻塞的。

    • ainaruto10
    • 2019/05/20 11:28下午

    完美

您必须 登陆 后才能发表评论

return top