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