2012-08-31 14 views
6

Czy istnieje sposób na określenie bieżącej milisekundy lub innej miary czasu, kiedy usługa Zaplanowane uruchamianie będzie uruchamiana w następnej kolejności?Określić, kiedy Zaplanowane uruchamianie usługi uruchomi się następująco:

scheduleTaskExecutorUpdate = Executors.newSingleThreadScheduledExecutor(); 

Mam już uruchomiony ScheduledExecutorService(A) iz krótszym biegu ScheduledExecutorService(B) Chciałbym zaktualizować TextView, wyświetli odliczanie kiedy ScheduledExecutorService(A) zamierza wystrzelić następnego.

Odpowiedz

8

Jeśli śledzisz numery ScheduledFuture s dla wszystkich zadań zaplanowanych dla executora, to tak. Staje się to problemem polegającym na określeniu minimalnego opóźnienia, dopóki nie zostanie uruchomione następne zadanie, które powinno być dość wiarygodnym oszacowaniem.

final Collection<ScheduledFuture<?>> futures = ...; 
/* for each schedule, add it to the above collection */ 
... 
final long delay = Collections.min(futures).getDelay(TimeUnit.MILLISECONDS); 

... albo na jednym zadaniu jedynie zrobić:

final ScheduledFuture<?> future = ...; 
final long delay = future.getDelay(TimeUnit.MILLISECONDS); 

Teraz, jeśli masz zamiar robić to dużo, z roznych zadań, bym sugeruję, abyś zachował DelayQueue. Jednak nie można po prostu wyrzucić s w kolejce bez zachowania zmian spowodowanych okresowymi zadaniami. Na szczęście klasa ScheduledThreadPoolExecutor powinna poradzić sobie z tym ładnie za pomocą metod decorateTask.

Uwaga: oznacza to, że należy bezpośrednio utworzyć własny ScheduledThreadPoolExecutor. Coś jak poniżej może działać.

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); 
    } 
    } 
} 

Następnie użycie jest następujące.

final TrackingSingleThreadScheduledExecutor executor 
    = new TrackingSingleThreadScheduledExecutor(); 
... 
final long delay = executor.next().getDelay(TimeUnit.MILLISECONDS); 
+0

+1 dobre rozwiązanie! – RNJ

+0

@RNJ mam nadzieję, że teraz jest jeszcze lepszym rozwiązaniem! – oldrinb

Powiązane problemy