Supressing redundant jobs in ScheduledThreadPoolExecutor
Asked Answered
L

3

2

I am using the ScheduledThreadPoolExecutor to execute periodic tasks. It is essential that the execution be periodic, not with fixed delay.

I encountered the following problem: consider a period of 1 minute for a task. If the task takes 5 minutes to execute (e.g. because of a temporary network problem), the missed executions get queued up and dispatched immediately after the task finishes. Is there a way to get rid of the accumulated executions that were missed?

I tried using the remove method, but it removes the task completely, not only a specific execution.

Thanks

Lamentation answered 8/8, 2012 at 12:46 Comment(0)
T
2

There might be a better way, but you could have your task reschedule itself. That way, one execution will always run 1 minute after the previous execution has finished:

final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable yourTask = new Runnable() {

    @Override
    public void run() {
        //do your stuff
        scheduler.schedule(this, 1, TimeUnit.MINUTES);
    }
};
scheduler.schedule(yourTask, 1, TimeUnit.MINUTES);

EDIT

If you want your task to run exactly at hh:mm:00 (exact minute) you can replace the code by

long millisToNextMinute = 60000 - System.currentTimeMillis() % 60000;
scheduler.schedule(this, millisToNextMinute, TimeUnit.MILLISECONDS);
Textual answered 8/8, 2012 at 12:51 Comment(6)
I thought of that but the period will drift, you could adjust the time to run next.Cynthiacynthie
@PeterLawrey He is asking to not run some of the periodic tasks, so there will be a time drift anyway. Unless he means that if the 13:01:00 task runs until 13:04:50, the next task should run at 13:05:00.Textual
And if he does, does it really matter.Cynthiacynthie
@assylias- you got it right. I do want the task to execute on exact multiples of its period. I was wondering whether I could do it without having to schedule myself.Lamentation
@Textual Shouldn't it be: period - Elapsed % period?Lamentation
@Lamentation Not sure I understand your question. System.currentTimeMillis() % 60000; is the number of milliseconds elapsed since the beginning of the current minute. 60000 - that quantity is the number of millis left before the next minute.Textual
R
1

You can build this logic into the task. Have the task record the last time it ran. Every time it starts, it should check whether enough time has passed since the last run. If not, then it should exit without doing any work.

Ralf answered 8/8, 2012 at 13:7 Comment(0)
S
0

In CronScheduler, there are SkippingToLatest methods (see Javadocs, "Skipping to latest runs" section that are particularly designed to handle this problem for you:

Duration syncPeriod = Duration.ofMinutes(1);
CronScheduler cron = CronScheduler.create(syncPeriod);
cron.scheduleAtFixedRateSkippingToLatest(0, 1, TimeUnit.MINUTES, runTimeMillis -> {
    // Do your task
});
Secondclass answered 29/1, 2020 at 14:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.