Is there a way to determine the current millisecond or other time measure of when a ScheduledExecutorService is going to fire next?
scheduleTaskExecutorUpdate = Executors.newSingleThreadScheduledExecutor();
I have a longer running ScheduledExecutorService(A)
and from a shorter running ScheduledExecutorService(B)
I would like to update a TextView, display a countdown of when ScheduledExecutorService(A)
is going to fire next.
If you keep track of the ScheduledFuture
s for all tasks scheduled with the executor, then yes. This becomes a problem of determining the minimum delay until the next task must fire, which should be a fairly reliable estimate.
final Collection<ScheduledFuture<?>> futures = ...;
/* for each schedule, add it to the above collection */
...
final long delay = Collections.min(futures).getDelay(TimeUnit.MILLISECONDS);
... or, for one task, you merely do:
final ScheduledFuture<?> future = ...;
final long delay = future.getDelay(TimeUnit.MILLISECONDS);
Now, if you're going to be doing it a lot, with mutiple tasks, I'd suggest you maintain a DelayQueue
. However, you can't merely throw the ScheduledFuture
s in the queue without maintaining the changes caused by periodic tasks. Luckily, the class ScheduledThreadPoolExecutor
should handle this nicely via its decorateTask
methods.
Note this means you will need to create your ownScheduledThreadPoolExecutor
directly. Something like the below might work.
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, usage is as follows.
final TrackingSingleThreadScheduledExecutor executor
= new TrackingSingleThreadScheduledExecutor();
...
final long delay = executor.next().getDelay(TimeUnit.MILLISECONDS);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With