I have a ScheduledExecutorService that I am using to run a method updateIndex() every one minute. However, if changes to resources are made during the one minute between the last refresh and the next refresh, I would like to have updateIndex() called immediately, and then have the executor service resume it's normal schedule; i.e. next update will take place in one minute. However, I haven't seen anything in the documentation to suggest there is the capability to do this. Any ideas?
public static void updateIndex() {
Runnable runnable = () -> {
//Do your logic here
};
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(runnable, 0, 1, TimeUnit.MINUTES);
}
According to JavaDocs
java.util.concurrent.ScheduledExecutorService.scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on. 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. If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
scheduleAtFixedRate() returns a ScheduledFuture which is a Future which has the cancel method you're looking for.
Related
I ask this question because there is a command that executes multiple times. Does it return a ScheduledFuture every time the command executes or does it return a single ScheduledFuture at some point?
Only a single ScheduledFuture<?> is returned upon scheduling the Runnable command.
According to the Javadoc, scheduleAtFixedRate returns
a ScheduledFuture representing pending completion of the series
of repeated tasks
You can also see this in the method signature:
ScheduledFuture<?> scheduleAtFixedRate​(Runnable command, long initialDelay, long period, TimeUnit unit)
The Runnable command continues to be executed according to the configured interval without further intervention.
The sequence of task executions continues indefinitely until one of
the following exceptional completions occur:
The task is explicitly cancelled via the returned future.
The executor terminates, also resulting in task cancellation.
An execution of the task throws an exception.
Having a single ScheduledFuture returned by scheduleAtFixedRate provides a useful mechanism to programmatically discontinue all future scheduled executions of Runnable command through a call to cancel on the Future.
I was looking at javadoc of --> java.util.concurrent.ScheduledExecutorService.scheduleAtFixedRate
I have re-produced below the javadoc:
ScheduledFuture<?> java.util.concurrent.ScheduledExecutorService.scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on. 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. If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
Parameters:
command the task to execute
initialDelay the time to delay first execution
period the period between successive executions
unit the time unit of the initialDelay and period parameters
Returns:
a ScheduledFuture representing pending completion of the task, and whose get() method will throw an exception upon cancellation
I understood that first time it would be enabled after initialDelay and then repeated after period. However, looking at highlighted section above, it seems frequency is increasing in-between the successive executions.
Is this the correct behaviour? If so, then the delay would get increased from previous executions?
Can anyone help clarify?
Issue:
I have a task which has to be run periodically with a fixed delay after each task is run. Also i have a condition
where in the initial delay or the first time execution should occur after a condition is met . So the executor must
prevent scheduling task until the condition is meet.
Java Concurrent package gives us ScheduledThreadPoolExecutor which has option for initial delay in time. But in my case
the initial delay is after some condition or value changes to desired one.
How can i achieve this behavior and what executorservice should i use or what methods in executor service can i override to achieve above behavior.
I don't want to start creating the ScheduledThreadPoolExecutor object only after the condition is meet , reason being that
there are large number of such periodic scheduled tasks which are present in our application and if any new task is added next time
and if they forget to added in code part where the check is made then it will be scheduled immediately without any condition check.
To avoid it i wanted an executor service which will handle it for me and next time anyone using this executorservice will by default get this
behavior for free.
Any help is appreciated.
Thank you
I don't think you will find readymade ExecutorService to handle your use-case. So why not try like this, create your custom class which extends ScheduledThreadPoolExecutor and there you override the beforeExecute method and here you write code to check for first time execution (have custom flag to check is it first execution or not) and than for other calls it will execute normal runnable object. Something similar to below code :
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TestClass extends ScheduledThreadPoolExecutor {
public TestClass(int corePoolSize) {
super(corePoolSize);
}
#Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
}
#Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
return super.schedule(command, initialDelay, TimeUnit.MILLISECONDS);
}
}
How about you create your executor in advance but only perform an operation of scheduling of task on pre-existing executor after your condition is met and you already know your desired initial delay.
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
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);
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.
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
});
When using
Timer.schedule(TimerTask task, long delay, long period)
(i.e. with fixed-delay execution), what happens if the specified TimerTask's run() method takes longer than period to complete? Is it possible that two concurrent TimerTask threads will be running because of this?
And if so, is there a way to avoid it?
Timer's documentation says the following:
Timer tasks should complete quickly. If a timer task takes excessive time to complete, it "hogs" the timer's task execution thread. This can, in turn, delay the execution of subsequent tasks, which may "bunch up" and execute in rapid succession when (and if) the offending task finally completes.
That is, concurrent TimerTask threads will not be running. The tasks will accumulate into a queue. This may or may not be appropriate (more likely, not).
Timer and TimerTask don't handle this sort of situation well. If you want to handle it better, then don't use those classes.
java.util.concurrent.ScheduledExecutorService provides two scheduling methods, scheduleAtFixedRate and scheduledWithFixedDelay, which govern what happens when tasks "bunch up".
scheduleAtFixedRate:
Creates and executes a periodic action
that becomes enabled first after the
given initial delay, and subsequently
with the given period; that is
executions will commence after
initialDelay then initialDelay+period,
then initialDelay + 2 * period, and so
on. 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. If any execution of this
task takes longer than its period,
then subsequent executions may start
late, but will not concurrently
execute.
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.
You can create ScheduledExecutorService instances using the Executors factory class.