If you track ScheduledFuture for all tasks scheduled with an artist, then yes. This becomes the problem of determining the minimum delay until the next task, which should be sufficiently reliable.
final Collection<ScheduledFuture<?>> futures = ...; ... final long delay = Collections.min(futures).getDelay(TimeUnit.MILLISECONDS);
... or, for one task, you simply do:
final ScheduledFuture<?> future = ...; final long delay = future.getDelay(TimeUnit.MILLISECONDS);
Now, if you are going to do this a lot, with several tasks, I suggest you support DelayQueue , you cannot just throw the ScheduledFuture into the queue without saving the changes caused by periodic tasks. Fortunately, the ScheduledThreadPoolExecutor class must handle this with decorateTask .
Please note: this means that you will need to create your own ScheduledThreadPoolExecutor directly. Perhaps something like below.
public class TrackingSingleThreadScheduledExecutor extends ScheduledThreadPoolExecutor { private final DelayQueue<ScheduledFuture<?>> tasks = new DelayQueue<RunnableScheduledFuture<?>>(); public TrackingSingleThreadScheduledExecutor() { super(1); } public DelayQueue<? extends ScheduledFuture<V>> tasks() { return tasks; } public ScheduledFuture<V> next() { return tasks.peek(); } protected <V> RunnableScheduledFuture<V> decorateTask (final Callable<V> callable, final RunnableScheduledFuture<V> task) { return new QueueAwareTask(task); } protected <V> RunnableScheduledFuture<V> decorateTask (final Runnable runnable, final RunnableScheduledFuture<V> task) { return new QueueAwareTask(task); } private final class QueueAwareTask<V> implements RunnableScheduledFuture<V> { private final RunnableScheduledFuture<V> inner; public QueueAwareTask(final RunnableScheduledFuture<V> inner) { this.inner = inner; } public boolean isPeriodic() { return inner.isPeriodic(); } public long getDelay(final TimeUnit unit) { return inner.getDelay(unit); } public void run() { inner.run(); if (queue.remove(inner) && inner.isPeriodic() && !inner.isCancelled()) { queue.add(inner); } } public int compareTo(final Delayed other) { return inner.compareTo(other); } public boolean cancel(final boolean mayInterruptIfRunning) { final boolean cancelled = inner.cancel(mayInterruptIfRunning); if (cancelled) { queue.remove(inner); } return cancelled; } public boolean isCancelled() { return inner.isCancelled(); } public boolean isDone() { return inner.isDone(); } public V get() throws InterruptedException, ExecutionException { return inner.get(); } public V get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException { return inner.get(timeout, unit); } } }
Then the following is used.
final TrackingSingleThreadScheduledExecutor executor = new TrackingSingleThreadScheduledExecutor(); ... final long delay = executor.next().getDelay(TimeUnit.MILLISECONDS);
source share