ScheduledExecutorService con ritardo variabile
-
19-09-2019 - |
Domanda
Supponiamo che io sono un compito che sta tirando gli elementi da un java.util.concurrent.BlockingQueue e il loro trattamento.
public void scheduleTask(int delay, TimeUnit timeUnit)
{
scheduledExecutorService.scheduleWithFixedDelay(new Task(queue), 0, delay, timeUnit);
}
Come posso programmare / riprogrammare l'attività se la frequenza può essere modificata in modo dinamico?
- L'idea è quella di prendere un flusso di aggiornamenti dei dati e li propagano in batch per una GUI
- L'utente deve essere in grado di variare la frequenza degli aggiornamenti
Soluzione
Non credo che si può cambiare un ritardo tasso fisso. Penso che è necessario utilizzare schedule () per eseguire una tantum e pianificazione nuovo una volta che ha completato (con un tempo modificato se richiesto).
Altri suggerimenti
Usa schedule(Callable<V>, long, TimeUnit)
piuttosto che scheduleAtFixedRate
o scheduleWithFixedDelay
. Quindi assicurarsi che il Callable se stesso o una nuova istanza Callable a un certo punto in futuro ripianifica. Ad esempio:
// Create Callable instance to schedule.
Callable<Void> c = new Callable<Void>() {
public Void call() {
try {
// Do work.
} finally {
// Reschedule in new Callable, typically with a delay based on the result
// of this Callable. In this example the Callable is stateless so we
// simply reschedule passing a reference to this.
service.schedule(this, 5000L, TimeUnit.MILLISECONDS);
}
return null;
}
}
service.schedule(c);
Questo approccio evita la necessità di spegnere e ricreare il ScheduledExecutorService
.
Non dovresti utilizzare scheduleAtFixedRate
se si sta cercando di elaborare diversi compiti di coda con un intervallo specifico? scheduleWithFixedDelay
attenderà solo per il ritardo specificato e quindi eseguire un compito dalla coda.
In entrambi i casi, i metodi schedule*
in ScheduledExecutorService
restituirà un riferimento ScheduledFuture
. Se si desidera cambiare la velocità, è possibile annullare l'ScheduledFuture
e riprogrammare l'attività con una tariffa diversa.
scheduleWithFixedDelay (...) restituisce un RunnableScheduledFuture. Al fine di riprogrammare esso, si potrebbe semplicemente annullare e riprogrammare esso. Per ripianificare esso, si può solo avvolgere il RunnableScheduledFuture uno spirito nuovo Runnable:
new Runnable() {
public void run() {
((RunnableScheduledFuture)future).run();
}
};
Ho dovuto fare questo di recente utilizzando ScheduledFuture e non volevo avvolgere Runnable o tali. Ecco come ho fatto:
private ScheduledExecutorService scheduleExecutor;
private ScheduledFuture<?> scheduleManager;
private Runnable timeTask;
public void changeScheduleTime(int timeSeconds){
//change to hourly update
if (scheduleManager!= null)
{
scheduleManager.cancel(true);
}
scheduleManager = scheduleExecutor.scheduleAtFixedRate(timeTask, timeSeconds, timeSeconds, TimeUnit.SECONDS);
}
public void someInitMethod() {
scheduleExecutor = Executors.newScheduledThreadPool(1);
timeTask = new Runnable() {
public void run() {
//task code here
//then check if we need to update task time
if(checkBoxHour.isChecked()){
changeScheduleTime(3600);
}
}
};
//instantiate with default time
scheduleManager = scheduleExecutor.scheduleAtFixedRate(timeTask, 60, 60, TimeUnit.SECONDS);
}