java ScheduledFuture getDelay возвращает отрицательное значение - PullRequest
0 голосов
/ 02 марта 2019

Я использую ScheduledExecutorService, Semaphore и ScheduledFuture для написания функции ограничения скорости, проще говоря, когда клиент достигает предела, сервер вернет ошибку 429 с сообщением «msg, пожалуйста, попробуйте через% d секунд».Я использую scheduleFuture.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 голосов
/ 06 марта 2019

scheduler.schedule() - это однократная функция, поэтому она показывает отрицательное значение getDelay().

0 голосов
/ 03 марта 2019

Если задание выполнено, 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));
}
...