Java Scheduling Example
This article will feature a comprehensive Example on Java scheduling. We will look into various ways of scheduling a task in Java with relevant code examples.
1. Introduction
In Computer Software, Scheduling is a paradigm of planning for an execution of a task at a certain point in time and it can be broadly classified into two types 1. One time scheduling wherein the task execution can be made once at a particular future point in time 2. Fixed Rate scheduling wherein the task execution can be made to repeat periodically at a fixed interval.
2. Java Scheduling
Java library provides various classes to schedule a thread or task that executes at a certain period of time once or periodically at a fixed interval and they are listed below.
java.util.TimerTask
java.util.concurrent.ScheduledExecutorService
Let us understand how to schedule tasks using the above library classes with code examples in the sections that follow.
2.1 Scheduling using TimerTask
TimerTask is an abstract class in java.util
package and it defines the task that can be scheduled for one-time or repeated execution by a Timer. java.util.Timer
is a utility class that can be used to schedule a thread to execute a TimerTask. Timer class is thread safe and multiple threads can share a single Timer object without need for external synchronization. Timer class uses java.util.TaskQueue
to add tasks at given regular interval and at any time there can be only one thread running the TimerTask.
Below is the code to instantiate Timer.
Timer timer = new Timer();
Timer class provides various methods to schedule TimerTask and one such method to schedule task after a fixed delay is below
public void schedule(TimerTask task, long delay)
In the above method signature, the task argument denotes TimerTask to be scheduled and the delay argument denotes the actual delay in milliseconds after which the task needs to be executed.
In order to define a concrete TimerTask object, it needs to be extended by custom task class and the run method need to be overridden. The run method is implicitly invoked when a timer object schedules it to do so.
Below is a simple program to schedule a one time task using TimerTask and Timer.
SchedulingUsingTimerTask
public class SchedulingUsingTimerTask extends TimerTask { @Override public void run() { System.out.println("Timer task executed :: " + new Date() + " :: " + Thread.currentThread().getName()); } public static void main(String[] args) throws ParseException { Timer timer = new Timer(); // Instantiates a timer to schedule tasks SchedulingUsingTimerTask task1 = new SchedulingUsingTimerTask(); // Task 1 Instantiation timer.schedule(task1, 5 * 1000); // Schedules task 1 for execution after the specified delay of 5 seconds SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss"); Date date = sdf.parse("04-09-2019 01:36:00"); SchedulingUsingTimerTask task2 = new SchedulingUsingTimerTask(); // Task 2 Instantiation timer.schedule(task2, date); // Schedules task 2 for execution at the particular time defined by date // timer.cancel(); // Terminates the Timer and cancels all the scheduled tasks } }
When the above code is executed, the timer task corresponding to a passed time interval gets executed immediately and another timer task which is scheduled gets executed after a delay of 5 seconds following which outputs are printed as presented in the below screenshot.
TimerTask provides various methods to schedule fixed rate tasks and one such method is stated below. The method takes TimerTask as the first argument, delay of execution in milliseconds being the second and period of repetition in milliseconds as the third argument.
public void scheduleAtFixedRate(TimerTask task, long delay, long period)
Below is the source code to demonstrate the fixed rate scheduling using TimerTask
FixedRateSchedulingUsingTimerTask
public class FixedRateSchedulingUsingTimerTask extends TimerTask { @Override public void run() { System.out.println("Fixed rate timer task executed :: " + new Date() + " :: " + Thread.currentThread().getName()); } public static void main(String[] args) { Timer timer = new Timer(); // Instantiating a timer object FixedRateSchedulingUsingTimerTask task1 = new FixedRateSchedulingUsingTimerTask(); // Creating a FixedRateSchedulingUsingTimerTask timer.scheduleAtFixedRate(task1, 2 * 1000, 2 * 1000); // Scheduling it to be executed with fixed rate at every two seconds FixedRateSchedulingUsingTimerTask task2 = new FixedRateSchedulingUsingTimerTask(); // Creating another FixedRateSchedulingUsingTimerTask timer.schedule(task2, 2 * 1000, 2 * 1000); // Scheduling it to be executed with fixed delay at every two seconds } }
In the above code, we schedule two tasks – one at fixed rate at every two seconds and another with fixed delay at every two seconds and when executed it produces output like below
2.2 Scheduling using ScheduledExecutorService
ScheduledExecutorService is an ExecutorService that can schedule tasks to run after a given delay, or to execute periodically. It is effectively a more versatile replacement for the Timer/TimerTask combination, as it allows multiple service threads, accepts various time units, and doesn’t require subclassing TimerTask (just implement Runnable). Configuring ScheduledExecutorService with one thread makes it equivalent to Timer.
ScheduledExecutorService is instantiated with initial number of threads like below
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3)
It provides various methods to schedule fixed rate tasks like below
ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
In the schedule methods above, Runnable task to be executed is passed as the first argument and initial delay represents the delay after which the task will be executed. In case of scheduleAtFixedRate, the task gets repeated after the defined period in the TimeUnit defined and in case of scheduleWithFixedDelay, delay in TimeUnit represents the fixed delay between the termination of one execution and the commencement of the next.
Below is the code to illustrate task scheduling using ScheduledExecutorService.
BeepControl
public class BeepControl { private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3); // ScheduledExecutorService created with 3 threads @SuppressWarnings("rawtypes") public static void beepForAnHour() { final Runnable beeper = new Runnable() { public void run() { System.out.println("beep :: " + new Date() ); } }; // Creating a new runnable task which will be passed as an argument to scheduler ScheduledFuture beeperHandleAtFixedRate = scheduler.scheduleAtFixedRate(beeper, 5, 5, SECONDS); // Creates and executes a ScheduledFuture that becomes enabled after 5 seconds and gets executed with fixed rate of 5 seconds ScheduledFuture beeperHandleArFixedDelay = scheduler.scheduleWithFixedDelay(beeper, 5, 5, SECONDS); // Creates and executes a ScheduledFuture that becomes enabled after 5 seconds and gets executed with fixed delay of 5 seconds scheduler.schedule(new Runnable() { public void run() { beeperHandleAtFixedRate.cancel(true); } // Attempts to cancel execution of task beeperHandleAtFixedRate after one hour }, 60 * 60, SECONDS); // Creates and executes a one-shot action that becomes enabled after the given delay. scheduler.schedule(new Runnable() { public void run() { beeperHandleArFixedDelay.cancel(true); } // Attempts to cancel execution of task beeperHandleArFixedDelay after one hour }, 60 * 60, SECONDS); } public static void main(String[] args) { beepForAnHour(); } }
The above code creates runnable, schedules them using ScheduledExecutorService with fixed delay and fixed rate to beep every 5 seconds. When the above code is executed, it prints beep statement at a fixed interval of 5 seconds for an hour like below
3. Differences between ScheduledExecutorService and TimerTask
ScheduledThreadPoolExecutor can be configured with any number of threads whereas TimerTask is executed by a single thread. Any delay in TimerTask execution can delay the other tasks in a schedule. Hence, it is not a viable option when multiple tasks need to be executed asynchronously at a certain time.
Also one of the main differences between them is the way exceptions are handled. When unchecked exceptions are thrown from the TimerTask execution the thread is killed, so following scheduled tasks won’t run further. But with ScheduledExecutorService only the current task will be canceled and the rest will continue to run.
4. Summary
In the article, we have understood with examples on how to schedule one time and fixed rate tasks using TimerTask which executes tasks in a single thread and using ScheduledExecutorService which executes tasks using an internal thread pool. We have understood the limitations of TimerTask when compared to ScheduledExecutorService and the main differences between them. This is a very good place to start for scheduling in Java and incase of a more scalable and complete solution for Java scheduling then other open source frameworks like Quartz can be explored.
5. Download the Source Code
This source contains the example code snippets used in this article to illustrate the Java Scheduling Example.
You can download the full source code of this example here: Java Scheduling Example
It is written that this article was published in September, 2019. But when was it written? It refers to class SimpleDateFormat which was replaced by the Java date-time API which was added in Java 8 which was first released in 2014.