我正在使用ScheduledExecutorService,Semaphore和ScheduledFuture编写一个速率限制功能,简单地说,当客户端达到限制时,服务器将返回错误429,消息为“ msg,请在%d秒后尝试”。 我使用ScheduledFuture.getDelay(TimeUnit.SECONDS)获取%d的值。对于第一次或第二次尝试,它均正常运行,即允许访问单元达到限制并显示随后要等待多少秒。然后getDelay开始显示负值。这是否意味着ScheduledExecutorService无法正常工作? 以下是代码段
public RateLimiter(int permits, long durationInMillis){
this.semaphore = new Semaphore(permits);
this.permits = permits;
this.durationInMillis = durationInMillis;
scheduleReplenishment();
}
public boolean allowAccess() {
return semaphore.tryAcquire();
}
public long nextReplenishmentTime() {
return scheduledFuture.getDelay(TimeUnit.SECONDS);
}
public void stop() {
scheduler.shutdownNow();
}
public void scheduleReplenishment() {
scheduledFuture = scheduler.schedule(() -> {
semaphore.release(permits - semaphore.availablePermits());
}, durationInMillis, TimeUnit.MILLISECONDS);
}
答案 0 :(得分:0)
如果任务已完成,则getDelay(TimeUnit)
将为负。为了显示它,我在scheduleReplenishment()
中添加了两个参数,并将getReplenishmentTime()
更改为printReplenishmentTime()
。
注意1:如果创建一个Future<>
,并用另一个替换,则应注意删除的一个...
注2:如果要测试Future<>
和Semaphore
,请不要立即释放分配的资源。
private final ConcurrentSkipListMap<String, ScheduledFuture<?>> scheduledFutures
= new ConcurrentSkipListMap<>();
private final AtomicInteger counter = new AtomicInteger();
public void printReplenishmentTime() {
scheduledFutures.forEach((name, f) -> {
final long delay = f.getDelay(TimeUnit.SECONDS);
System.out.println(name + " delay " + delay);
});
}
/**
* try acquire one permit once from {@code semaphore},
* then wait {@code waitInMillis}, until all permits used.
*
* @param waitInMillis after successfully used one permit, wait
* @param permits all permits to use, best if permits @gt; 2
*/
public void scheduleReplenishment(final long waitInMillis, final int permits) {
final String name = "future" + counter.getAndIncrement();
scheduledFutures.put(name, scheduler.schedule(() -> {
try {
for (int permit = permits; 0 < permit;) {
final boolean ack = semaphore.tryAcquire(1);
System.out.println(name + " " + (ack ? "acquire" : "not acquire")
+ " one, but need " + permit);
if (ack) {
permit--;
}
if (0 < permit) {
try {
Thread.sleep(waitInMillis);
} catch (final InterruptedException e) {
System.out.println(name + " interrupted, exiting...");
return;
}
}
}
System.out.println(name + " done");
} finally {
semaphore.release(permits - permit);
}
// BAD CODE: semaphore.availablePermits() for debugging purposes
// only, maybe 0 release...
// semaphore.release(permits - semaphore.availablePermits());
}, durationInMillis, TimeUnit.MILLISECONDS));
}
答案 1 :(得分:0)
scheduler.schedule()
是一次性函数,因此它显示负getDelay()
值。