views:

691

answers:

4

Suppose I have a task that is pulling elements from a java.util.concurrent.BlockingQueue and processing them.

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

How can I schedule / reschedule the task if the frequency can be changed dynamically?

  • The idea is to take a stream of data updates and propagate them in batch to a GUI
  • The user should be able to vary the frequency of updates
A: 

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.

jarnbjo
scheduleWithFixedDelay(...) - Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next. If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor.
parkr
Can you give a code example of cancelling and rescheduling? What about any updates in progress?
parkr
+1  A: 

I don't think you can change a fixed rate delay. I think you need to use schedule() to perform a one-shot, and schedule again once that has completed (with a modified time out if required).

Brian Agnew
Thanks - I made 'delay' an instance variable and added a private method to do the following: while(!executorService.isShutdown) { executorService.schedule(new Task(queue), delay, TimeUnit.MILLISECONDS); }
parkr
A: 

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();
    }
};
sfussenegger
+2  A: 

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

service.schedule(c);

This approach avoids the need to shut down and recreate the ScheduledExecutorService.

Adamski