java ScheduledFuture getDelay返回负值

时间:2019-03-02 11:32:06

标签: java semaphore scheduledexecutorservice

我正在使用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);    
}

2 个答案:

答案 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()值。