PredulleDexeCutorService с переменной задержкой
-
19-09-2019 - |
Вопрос
Предположим, у меня есть задача, которая вытаскивает элементы из java.util.concurrent.blockqueue и их обработка.
public void scheduleTask(int delay, TimeUnit timeUnit)
{
scheduledExecutorService.scheduleWithFixedDelay(new Task(queue), 0, delay, timeUnit);
}
Как я могу запланировать / перенести задачу, если частота может быть изменена динамически?
- Идея состоит в том, чтобы взять поток обновлений данных и распространить их в партии в графический интерфейс
- Пользователь должен иметь возможность изменять частоту обновлений
Решение
Я не думаю, что вы можете изменить задержку с фиксированной ставкой. Я думаю, тебе нужно использовать расписание() Чтобы выполнить один выстрел и снова запланировать после завершения (с измененным временем, если это необходимо).
Другие советы
Use schedule(Callable<V>, long, TimeUnit)
rather than scheduleAtFixedRate
or scheduleWithFixedDelay
. Then ensure that your Callable reschedules itself or a new Callable instance at some point in the future. For example:
// 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);
This approach avoids the need to shut down and recreate the ScheduledExecutorService
.
Shouldn't you be using scheduleAtFixedRate
if you are trying to process several queue tasks with a specific interval? scheduleWithFixedDelay
will only wait for the specified delay and then execute one task from the queue.
In either case, the schedule*
methods in a ScheduledExecutorService
will return a ScheduledFuture
reference. If you want to change the rate, you can cancel the ScheduledFuture
and reschedule the task with a different rate.
scheduleWithFixedDelay(...) returns a RunnableScheduledFuture. In order to reschedule it, you might just cancel and reschedule it. To reschedule it, you may just wrap the RunnableScheduledFuture wit a new Runnable:
new Runnable() {
public void run() {
((RunnableScheduledFuture)future).run();
}
};
I had to do this recently using ScheduledFuture and didn't want to wrap Runnable or such. Here's how I did it:
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);
}