The Java Executor Framework provides the ThreadPoolExecutor
class to execute Callable
and Runnable
tasks with a pool of threads, which avoid you writing lots of boiler plate complex code. The way executors work is when you send a task to the executor, it’s executed as soon as possible. But there may be used cases when you are not interested in executing a task as soon as possible. Rather You may want to execute a task after a period of time or to execute a task periodically. For these purposes, the Executor framework provides the ScheduledThreadPoolExecutor
class.
Task to be executed
Let’s write a very basic task which we can use for demo purpose.
class Task implements Runnable { private String name; public Task(String name) { this.name = name; } public String getName() { return name; } @Override public void run() { try { System.out.println("Doing a task during : " + name + " - Time - " + new Date()); } catch (Exception e) { e.printStackTrace(); } } }
Execute a task after a period of time
package com.howtodoinjava.demo.multithreading; import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ScheduledThreadPoolExecutorExample { public static void main(String[] args) { ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); Task task1 = new Task ("Demo Task 1"); Task task2 = new Task ("Demo Task 2"); System.out.println("The time is : " + new Date()); executor.schedule(task1, 5 , TimeUnit.SECONDS); executor.schedule(task2, 10 , TimeUnit.SECONDS); try { executor.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); } executor.shutdown(); } } Output: The time is : Wed Mar 25 16:14:07 IST 2015 Doing a task during : Demo Task 1 - Time - Wed Mar 25 16:14:12 IST 2015 Doing a task during : Demo Task 2 - Time - Wed Mar 25 16:14:17 IST 2015
As with class ThreadPoolExecutor
, to create a scheduled executor, Java recommends the utilization of the Executors
class. In this case, you have to use the newScheduledThreadPool()
method. You have passed the number 1 as a parameter to this method. This parameter is the number of threads you want to have in the pool.
To execute a task in this scheduled executor after a period of time, you have to use the schedule()
method. This method receives the following three parameters:
- The task you want to execute
- The period of time you want the task to wait before its execution
- The unit of the period of time, specified as a constant of the TimeUnit class
Also note that You can also use the Runnable
interface to implement the tasks, because the schedule()
method of the ScheduledThreadPoolExecutor
class accepts both types of tasks.
Moreover ,although the ScheduledThreadPoolExecutor
class is a child class of the ThreadPoolExecutor
class and, therefore, inherits all its features, Java recommends the utilization of ScheduledThreadPoolExecutor
only for scheduled tasks.
Finally, you can configure the behavior of the ScheduledThreadPoolExecutor
class when you call the shutdown()
method and there are pending tasks waiting for the end of their delay time. The default behavior is that those tasks will be executed despite the finalization of the executor. You can change this behavior using the setExecuteExistingDelayedTasksAfterShutdownPolicy()
method of the ScheduledThreadPoolExecutor
class. With false, at the time of shutdown()
, pending tasks won’t get executed.
Execute a task periodically
Now let’s learn how to use ScheduledThreadPoolExecutor
to schedule a periodic task.
public class ScheduledThreadPoolExecutorExample { public static void main(String[] args) { ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); Task task1 = new Task ("Demo Task 1"); System.out.println("The time is : " + new Date()); ScheduledFuture<?> result = executor.scheduleAtFixedRate(task1, 2, 5, TimeUnit.SECONDS); try { TimeUnit.MILLISECONDS.sleep(20000); } catch (InterruptedException e) { e.printStackTrace(); } executor.shutdown(); } } Output: The time is : Wed Mar 25 16:20:12 IST 2015 Doing a task during : Demo Task 1 - Time - Wed Mar 25 16:20:14 IST 2015 Doing a task during : Demo Task 1 - Time - Wed Mar 25 16:20:19 IST 2015 Doing a task during : Demo Task 1 - Time - Wed Mar 25 16:20:24 IST 2015 Doing a task during : Demo Task 1 - Time - Wed Mar 25 16:20:29 IST 2015
In this example, we have created ScheduledExecutorService
instance just like above example using newScheduledThreadPool()
method. Then we have used the scheduledAtFixedRate()
method. This method accepts four parameters:
- the task you want to execute periodically,
- the delay of time until the first execution of the task,
- the period between two executions,
- and the time unit of the second and third parameters.
An important point to consider is that the period between two executions is the period of time between these two executions that begins. If you have a periodic task that takes 5 seconds to execute and you put a period of 3 seconds, you will have two instances of the task executing at a time.
ScheduledThreadPoolExecutor
provides other methods to schedule periodic tasks. It is the scheduleWithFixedRate() method. It has the same parameters as the scheduledAtFixedRate()
method, but there is a difference worth noticing. In the scheduledAtFixedRate()
method, the third parameter determines the period of time between the starting of two executions. In the scheduledWithFixedRate()
method, parameter determines the period of time between the end of an execution of the task and the beginning of the next execution.You can also configure the behavior of an instance of the ScheduledThreadPoolExecutor
class with the shutdown()
method. The default behavior is that the scheduled tasks finish when you call that method. You can change this behavior using the setContinueExistingPeriodicTasksAfterShutdownPolicy()
method of the ScheduledThreadPoolExecutor
class with a true value. The periodic tasks won’t finish upon calling the shutdown()
method.
Happy Learning !!
Naseem Malik
is there any way we can change schedule interval after he start of program. For example, I want to change execution time of a task from 1 AM daily to 2 AM daily.
Sudeer Verma
Nice one..Really helpful
Chetan
Thanks for your post , these posts on individual topics are very helpful in understanding and later we can mix them for the desired functionality.
Just one correction, In the Note section you might have done Typo and hence it shows “scheduledWithFixedRate” instead of “scheduleWithFixedDelay”.
Mukundhan
“If you have a periodic task that takes 5 seconds to execute and you put a period of 3 seconds, you will have two instances of the task executing at a time.” – No two tasks execute at the same time. [Please refer to 5.3 this post] In this case, the subsequent execution happens at every 5 seconds though the delay is 3 seconds. Thanks.
Sagar
Thanks Mukundhan for the correction.
dz
The 1st example, should we put
executor.shutdown();
before
executor.awaitTermination(1, TimeUnit.DAYS);
so the executor can exit after all tasks are done rather than waiting for a day?
Siddharth Verma
awaitTermination(long timeout, TimeUnit unit)
Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
Teja
IN Execute a task periodically program , the output has 4 statements. Is there any reason why the task executed for 4 times ? Can we configure how many times it should execute ?
Lokesh Gupta
I had closed the program after 4 executions. If you let it run indefinitely, it will be executed unlimited number of times.
sp
Can you please let me know where have you initiated to close the program after 4th run?
Belal R
It will run indefinitely and we are only forcing it to stop executing after 4 times using sleep method.If we change the seconds in sleep from 20 to 30 then it will run 6 times and it will shutdown. Hope u guys Understand!!!!