番石榴速率限制器在超时设置为 >= 1 秒时不起作用



我正在使用Guava RateLimiter,并且已经在我的代码中创建了RateLimiter,如下所示。

public class RateLimitedCallable<T> implements Callable<T> {
@Override
public T call() {
Boolean permitAcquired = RateLimitTest.rateLimiter.tryAcquire(1, 1000,
TimeUnit.MILLISECONDS);
if (permitAcquired) {
// do stuff
} else {
throw new RuntimeException("Permit was not granted by RateLimiter");
}
}
}
public class RateLimitTest {
public static final RateLimiter rateLimiter = RateLimiter.create(1.0);
public void test() {
RateLimitedCallable<String> callable = new RateLimitedCallable<>();
callable.call();
callable.call();
callable.call();
callable.call();
}
public static void main(String[] args) {
RateLimitTest limiterTest = new RateLimitTest();
limiterTest.test();
} 
}

RuntimeException从不被抛出。但是,如果我将超时更改为低于1000 ms的值,例如:-

Boolean permitAcquired = RateLimitTest.rateLimiter.tryAcquire(1, 900, TimeUnit.MILLISECONDS);

我确实看到了RunTimeException,这意味着速率限制器按预期工作。我不明白为什么当超时时间大于等于1000ms时,限速器不强制限制。我做错了什么吗?

首先,最好记住tryAcquire的作用(重点是我的):

在不超过指定的timeout的情况下,从该RateLimiter获得给定数量的许可,或者立即返回false(不等待),如果在超时之前没有授予许可。

在单线程示例中,它从不抛出任何异常是正常的,因为每个调用在获得许可之前大约等待一秒钟。下面是你的代码:

  1. 第一个调用知道它可以立即获得许可。因此,它立即获得许可。
  2. 在第一个调用完全完成后,第二个调用知道如果等待它可以获得许可。因此,它等待~1s并获得许可。
  3. 在第二个调用完全完成后,第三个调用知道如果等待它可以获得许可。因此,它等待~1s并获得许可。
  4. 在第三个调用完全完成后,第四个调用知道如果等待就可以获得许可。所以它等待~1s,并获得许可
  5. 程序结束

现在尝试在多线程示例中使用此方法,您将开始看到一些失败和一些成功。因为他们都想同时获得许可证。

  1. 第一个获得的是快乐的。
  2. 然后第二个知道如果它等待1秒,它可以得到它,所以它等待直到它得到它。
  3. 第三个和第四个看到队列中已经有2个调用,并且知道他们必须等待2秒才能获得许可。所以他们放弃了,因为2秒大于你设置的1秒超时。

基本上,使用一个多线程环境来测试它是否会发生

@Test
void test() {
var rateLimiter = RateLimiter.create(1.0);
var stopwatch = Stopwatch.createStarted();
var executor = Executors.newFixedThreadPool(4);
for (var i = 0; i < 4; i++) {
executor.submit(() -> {
if (rateLimiter.tryAcquire(1, 1000, TimeUnit.MILLISECONDS)) {
System.out.printf("Acquired after %s%n", stopwatch);
} else {
System.out.printf("Gave up trying to acquire after %s%n", stopwatch);
}
});
}
executor.shutdown();
try {
if (!executor.awaitTermination(5000, TimeUnit.MILLISECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}

结果是

Acquired after 12.76 ms
Gave up trying to acquire after 12.41 ms
Gave up trying to acquire after 12.43 ms
Acquired after 1.004 s

最新更新