Si realiza un seguimiento de ScheduledFuture
s para todas las tareas programadas con el ejecutor, entonces sí. Esto se convierte en un problema para determinar la demora mínima hasta que la siguiente tarea debe dispararse, lo que debería ser una estimación bastante confiable.
final Collection<ScheduledFuture<?>> futures = ...;
/* for each schedule, add it to the above collection */
...
final long delay = Collections.min(futures).getDelay(TimeUnit.MILLISECONDS);
... o, para una tarea, simplemente haces:
final ScheduledFuture<?> future = ...;
final long delay = future.getDelay(TimeUnit.MILLISECONDS);
Ahora, si vas a estar haciendo un montón , con mutiple tareas, que había sugerimos que mantenga un DelayQueue
. Sin embargo, no puede simplemente tirar el ScheduledFuture
s en la cola sin mantener los cambios causados por las tareas periódicas. Afortunadamente, la clase ScheduledThreadPoolExecutor
debe manejar esto muy bien a través de sus métodos decorateTask
.
Tenga en cuenta que esto significa que tendrá que crear su propio ScheduledThreadPoolExecutor
directamente. Algo como lo de abajo podría funcionar.
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);
}
}
}
Luego, el uso es el siguiente.
final TrackingSingleThreadScheduledExecutor executor
= new TrackingSingleThreadScheduledExecutor();
...
final long delay = executor.next().getDelay(TimeUnit.MILLISECONDS);
+1 buena solución! – RNJ
@RNJ ¡ojalá sea una solución aún mejor ahora! – oldrinb