ScheduledExecutorService с переменной задержкой - PullRequest
18 голосов
/ 05 октября 2009

Предположим, у меня есть задача, которая извлекает элементы из java.util.concurrent.BlockingQueue и обрабатывает их.

public void scheduleTask(int delay, TimeUnit timeUnit)
{
    scheduledExecutorService.scheduleWithFixedDelay(new Task(queue), 0, delay, timeUnit);
}

Как я могу запланировать / перепланировать задачу, если частота может быть изменена динамически?

  • Идея состоит в том, чтобы взять поток обновлений данных и распространить их в пакетном режиме в графический интерфейс
  • Пользователь должен иметь возможность изменять частоту обновлений

Ответы [ 5 ]

26 голосов
/ 05 октября 2009

Используйте schedule(Callable<V>, long, TimeUnit) вместо scheduleAtFixedRate или scheduleWithFixedDelay. Затем убедитесь, что ваш Callable перенесет себя или новый экземпляр Callable в какой-то момент в будущем. Например:

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

Этот подход исключает необходимость выключения и воссоздания ScheduledExecutorService.

7 голосов
/ 05 октября 2009

Не думаю, что вы можете изменить задержку с фиксированной ставкой. Я думаю, что вам нужно использовать schedule () для выполнения однократного выстрела и планировать снова после завершения (с измененным временем ожидания, если требуется).

2 голосов
/ 05 октября 2009

Не следует ли использовать scheduleAtFixedRate, если вы пытаетесь обработать несколько задач очереди с определенным интервалом? scheduleWithFixedDelay будет только ждать указанной задержки, а затем выполнит одну задачу из очереди.

В любом случае методы schedule* в ScheduledExecutorService вернут ссылку ScheduledFuture. Если вы хотите изменить ставку, вы можете отменить ScheduledFuture и перенести задачу с другой ставкой.

0 голосов
/ 10 октября 2018

Я должен был сделать это недавно, используя ScheduledFuture и не хотел оборачивать Runnable или что-то подобное. Вот как я это сделал:

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);
}
0 голосов
/ 05 октября 2009

scheduleWithFixedDelay (...) возвращает RunnableScheduledFuture. Чтобы перенести его, вы можете просто отменить и перенести его. Чтобы перенести его, вы можете просто обернуть RunnableScheduledFuture новым Runnable:

new Runnable() {
    public void run() {
        ((RunnableScheduledFuture)future).run();
    }
};
...