ScheduledThreadPoolExecutor scheduleWithFixedDelay and urgent execution

I have the following problem: the standard library doesn’t work very well, and I’m wondering if anyone saw another library there with what it can be done, so I don’t have to crack my own solution. I have a task that is currently scheduled in a thread pool using scheduleWithFixedDelay (), and I need to change the code to process requests for urgent execution of a task related to asynchronous events. Thus, if the task is scheduled for a delay of 5 minutes between execution, and the event occurs 2 minutes after the last completed execution, I would like to immediately execute the task, and then wait for 5 minutes after completion the urgent execution before restarting. Currently, the best solution I can come up with is to call the cancel () event handler in the ScheduledFuture object returned by scheduleWithFixedDelay () and immediately execute the task and then set a flag in the task to inform it of its rescheduling with the same delay parameters . Is this functionality already available, and I just missed something in the documentation?

+6
java
source share
2 answers

If you are using ScheduledThreadPoolExecutor , there is a decorateTask method (there are actually two, for Runnable and Callable tasks) that you can override to store a reference to the task somewhere.

When you need urgent execution, you simply call run() on this link, which forces it to run and transfer with the same delay.

Quick hack attempt:

  public class UrgentScheduledThreadPoolExecutor extends
         ScheduledThreadPoolExecutor {
     RunnableScheduledFuture scheduledTask;

     public UrgentScheduledThreadPoolExecutor (int corePoolSize) {
         super (corePoolSize);
     }

     @Override
     protected RunnableScheduledFuture decorateTask (Runnable runnable,
             RunnableScheduledFuture task) {
         scheduledTask = task;
         return super.decorateTask (runnable, task);
     }

     public void runUrgently () {
         this.scheduledTask.run ();
     }
 } 

which can be used as follows:

  public class UrgentExecutionTest {

     public static void main (String [] args) throws Exception {
         UrgentScheduledThreadPoolExecutor pool = new UrgentScheduledThreadPoolExecutor (5);

         pool.scheduleWithFixedDelay (new Runnable () {
             SimpleDateFormat format = new SimpleDateFormat ("ss"); 

             @Override
             public void run () {
                 System.out.println (format.format (new Date ()));
             }
         }, 0, 2L, TimeUnit.SECONDS);
         Thread.sleep (7000);
         pool.runUrgently ();
         pool.awaitTermination (600, TimeUnit.SECONDS);
     }
 } 

and displays the following result: 06 08 10 11 13 15

+6
source share

as requested (soz, in a hurry) my EventBasedExecutor

Warning: Currently, this only works for tasks scheduled in batch mode. You can change the code to handle all tasks, I still do not have, because I only have the task of periodic launching. I also run this on a stream with an alias (I only need one scheduled runners stream that runs on one dedicated thread every X every time)

Here we go:

 public class EventBasedExecutor extends ScheduledThreadPoolExecutor implements EventBasedExecutorService { private List<RunnableScheduledFuture<?>> workers = new ArrayList<>(); private int index; public EventBasedExecutor(int corePoolSize) { super(corePoolSize, new ThreadFactoryBuilder().setDaemon(true).setNameFormat("message-sender-%d").build()); } @Override protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) { if(!workers.contains(runnable)) { workers.add(task); } return super.decorateTask(runnable, task); } @Override public void executeEarly() { if(index >= workers.size()) { index = 0; } if(workers.size() == 0) { return; } RunnableScheduledFuture<?> runnableScheduledFuture = workers.get(index); index ++; execute(runnableScheduledFuture); System.out.println("Executing"); } public static void main(String[] args) throws InterruptedException { EventBasedExecutor executor = new EventBasedExecutor(10); long currentTimeMillis = System.currentTimeMillis(); // this will never run executor.scheduleAtFixedRate(() -> { System.out.println("hello"); }, 5000, 5000, TimeUnit.HOURS); executor.executeEarly(); System.out.println("Run after: " + (System.currentTimeMillis() - currentTimeMillis)); } } 

This will complete the task in the dedicated workflow.

He will print:

 Executing hello Run after: 39 

Have fun hacking :)

artur

0
source share

All Articles