Agendado ExecutorService com atraso variável
-
19-09-2019 - |
Pergunta
Suponha que eu tenha uma tarefa que esteja puxando elementos de um java.util.Concurrent.BlockingQueue e processando -os.
public void scheduleTask(int delay, TimeUnit timeUnit)
{
scheduledExecutorService.scheduleWithFixedDelay(new Task(queue), 0, delay, timeUnit);
}
Como posso agendar / reagendar a tarefa se a frequência puder ser alterada dinamicamente?
- A idéia é fazer um fluxo de atualizações de dados e propagá -las em lote para uma GUI
- O usuário deve poder variar a frequência de atualizações
Solução
Eu não acho que você possa alterar um atraso de taxa fixa. Eu acho que você precisa usar cronograma() Para executar um único tiro e agendar novamente uma vez que ele conclua (com um tempo limite modificado, se necessário).
Outras dicas
Usar schedule(Callable<V>, long, TimeUnit)
ao invés de scheduleAtFixedRate
ou scheduleWithFixedDelay
. Em seguida, verifique se o seu chamável reagendas em si ou uma nova instância chamada em algum momento no futuro. Por exemplo:
// 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);
Essa abordagem evita a necessidade de desligar e recriar o ScheduledExecutorService
.
Você não deveria estar usando scheduleAtFixedRate
Se você está tentando processar várias tarefas de fila com um intervalo específico? scheduleWithFixedDelay
aguardará apenas o atraso especificado e executará uma tarefa da fila.
Em ambos os casos, o schedule*
Métodos em a ScheduledExecutorService
retornará um ScheduledFuture
referência. Se você quiser alterar a taxa, pode cancelar o ScheduledFuture
e reagendar a tarefa com uma taxa diferente.
SchedulewithFixedDelay (...) retorna um RunnablesCheduledFuture. Para reagendar, você pode apenas cancelar e reagir. Para reagendar, você pode apenas embrulhar o RunnablesCheduledFuture com um novo Runnable:
new Runnable() {
public void run() {
((RunnableScheduledFuture)future).run();
}
};
Eu tive que fazer isso recentemente usando o ScheduledFuture e não queria envolver o Runnable ou algo assim. Veja como eu fiz:
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);
}