ScheduledExecutorService con retardo variable
-
19-09-2019 - |
Pregunta
Supongamos que tengo una tarea que está tirando de los elementos de un java.util.concurrent.BlockingQueue y tratamiento.
public void scheduleTask(int delay, TimeUnit timeUnit)
{
scheduledExecutorService.scheduleWithFixedDelay(new Task(queue), 0, delay, timeUnit);
}
¿Cómo puedo programar / reprogramar la tarea si la frecuencia se puede cambiar dinámicamente?
- La idea es tener un flujo de actualizaciones de datos y propagarlas en el lote a una interfaz gráfica de usuario
- El usuario debe ser capaz de variar la frecuencia de cambios
Solución
No creo que se puede cambiar un retardo de tipo fijo. Creo que es necesario utilizar schedule () para llevar a cabo un one-shot, y el horario de nuevo una vez que se ha completado (con una hora de modificación si se requiere).
Otros consejos
Uso schedule(Callable<V>, long, TimeUnit)
en lugar de scheduleAtFixedRate
o scheduleWithFixedDelay
. A continuación, asegúrese de que su rescatable reprograma sí misma o una nueva instancia rescatable en algún momento en el futuro. Por ejemplo:
// 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);
Este enfoque evita la necesidad de apagar y volver a crear la ScheduledExecutorService
.
No deberías estar usando scheduleAtFixedRate
si usted está tratando de procesar varias tareas de la cola con un intervalo específico? scheduleWithFixedDelay
sólo se esperará a que el retardo especificada y luego ejecutar una tarea de la cola.
En cualquier caso, los métodos schedule*
en un ScheduledExecutorService
volverán una referencia ScheduledFuture
. Si desea cambiar la velocidad, se puede cancelar el ScheduledFuture
y volver a programar la tarea con un ritmo diferente.
scheduleWithFixedDelay (...) devuelve un RunnableScheduledFuture. Con el fin de volver a programarlo, que sólo podría cancelar y volver a programarlo. Para volver a programarlo, es posible que sólo envolver el ingenio RunnableScheduledFuture un nuevo Ejecutable:
new Runnable() {
public void run() {
((RunnableScheduledFuture)future).run();
}
};
he tenido que hacer esto utilizando recientemente ScheduledFuture y no quería envolver Ejecutable o algo así. Así es como lo hice:
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);
}