Java Timer example
In this example, we will learn about the Timer
class available under the java.util
package.
The Timer
facilitates the execution of tasks in a background thread. The tasks to be executed by the Timer
can be chosen either to be a one-time execution OR a repeated execution at pre-defined intervals.
Along with the mentioned execution frequency of the task, the scheduling time / delay of these tasks can also be optionally mentioned to the Timer
class.
Representing what is stated above, the TimerTask
to be executed can be:
- One-time execution which in turn can be:
- Scheduled immediately
- Scheduled to start after a delay
- Repeated execution at regular intervals which in turn can be:
- Scheduled immediately
- Scheduled to start after a delay
Components of Timer
We would briefly look at the internal components of the Timer
class. In terms of usage, one only needs to create Tasks by extending the TimerTask
and schedule them with the Timer
instance.
The other two internal components – TaskQueue
and TimerThread
have been mentioned below for information purpose, so as to help one evaluate when and for what kind of tasks should the Timer
class be used.
Task Queue
Timer Thread
Timer Task
Internally, the Timer
uses the TaskQueue
as a “priority” queue maintaining tasks in the order of next execution. The priority queue holds task in the sequence they should be executed by the TimerThread
.
The TimerThread
is a thread helper class which repeatedly monitors the TaskQueue
and “sequentially” executes the tasks based on their execution order and time of execution. To note here, the Timer
has only one instance of the TimerThread
internally. Thus, if any of the scheduled Timer
tasks takes excessive time to run, the other tasks scheduled for execution will keep waiting till the offending task completes. The waiting tasks may then be executed in rapid successions by the TimerThread
causing unexpected results.
The TimerTask
is the actual unit of task that needs to be performed by the Timer
for either once or multiple times at regular intervals. The TimerTask
is an abstract class implementing Runnable. As a user of the Timer
, one needs to extend this class and implement the run method by providing the logic of the task that needs to be performed.
Now, let us look at an example using the Timer
. In the example, we create two TimerTask
:
- A
TimerTask
in a slave node which sends some heart-beat information at an interval of 10 seconds. The task is scheduled to start with a delay of 1 second. - A
TimerTask
which updates the status being sent by the first task to AMBER. This task is executed once after a delay of 30 seconds.
Let’s look at TimerTask
#1, TimerTaskSendHeartBeat
for heartbeat sending.
class TimerTaskSendHeartBeat extends TimerTask { TimerExample healthStatusHolder = null; public TimerTaskSendHeartBeat(TimerExample healthStatusHolder) { this.healthStatusHolder = healthStatusHolder; } HeartBeatMessage message = null; @Override public void run() { // create HeartBeat message by getting Health Status (RED/GREEN/AMBER) // Error Code, if any AND time at which heartbeat is sent to help // receiver discard any delayed messages due to latency message = new HeartBeatMessage( this.healthStatusHolder.getHealthStatus(), Calendar .getInstance().getTimeInMillis(), -1); System.out.println("Sending HeartBeat Message"); // Send the message to Monitoring Dashboard System.out.println(message); System.out.println("HeartBeat Message Sent"); } /** * Simple POJO which is a heartbeat message object It can have any decoder * encoder mechanism to send over any messaging platform */ class HeartBeatMessage { private String status; private long heartBeatTime; private int errorCode; public HeartBeatMessage(String status, long heartBeatTime, int errorCode) { this.status = status; this.heartBeatTime = heartBeatTime; this.errorCode = errorCode; } public String getStatus() { return status; } public long getHeartBeatTime() { return heartBeatTime; } public int getErrorCode() { return errorCode; } @Override public String toString() { return "status: " + status + " timeOfHeartBeat: " + new java.util.Date(this.heartBeatTime) + " errCode : " + this.errorCode; } }
Below is the implementation of the TimerTask
# 2, TimerTaskUpdateHeartBeat
which just updates the status of the heartbeat message being sent.
class TimerTaskUpdateHeartBeat extends TimerTask { TimerExample healthClass = null; public TimerTaskUpdateHeartBeat(TimerExample healthClass) { this.healthClass = healthClass; } @Override public void run() { System.out.println("Task 2:: 30 seconds completed :: Updating health " + "status to AMBER"); healthClass.setHealthStatus("AMBER"); } }
Once both the TimerTask
have been created, let us know schedule the tasks at the desired time and frequency of execution. This would require creating a new Timer
instance and scheduling tasks to it.
public class TimerExample { private String healthStatus = "GREEN"; public static void main(String[] args) { TimerExample example = new TimerExample(); example.setHealthStatus("GREEN"); // Create the Timer object Timer timer = new Timer("JCG Timer Example"); // Create Timer task created to send heartBeats TimerTask taskToExecute = new TimerTaskSendHeartBeat(example); // schedule the task to start executing after 1 second // and re-execute every 10 seconds timer.scheduleAtFixedRate(taskToExecute, 1000, 10000); // Create Timer task to setHeartBeatStatus TimerTask setHeartBeatStatus = new TimerTaskUpdateHeartBeat(example); // schedule the task to start immediately but execute // first time after 30 seconds timer.schedule(setHeartBeatStatus, 30000); // Wait for 60 seconds and then cancel the timer cleanly try { Thread.sleep(60000); } catch (InterruptedException e) { } System.out.println("Cancelling Timer Cleanly after 60 seconds"); timer.cancel(); } /** * Get Heartbeat Status of the application, could be GREEN / AMBER / RED * based on any exceptions or service health * * @return String */ public String getHealthStatus() { return this.healthStatus; } /** * Set the status for the application could be GREEN / AMBER / RED * * @param healthStatus */ public void setHealthStatus(String healthStatus) { this.healthStatus = healthStatus; } }
On execution of the program, the output looks as below:
Sending HeartBeat Message status: GREEN timeOfHeartBeat: Mon Jun 16 23:52:04 IST 2014 errCode : -1 HeartBeat Message Sent Sending HeartBeat Message status: GREEN timeOfHeartBeat: Mon Jun 16 23:52:14 IST 2014 errCode : -1 HeartBeat Message Sent Sending HeartBeat Message status: GREEN timeOfHeartBeat: Mon Jun 16 23:52:24 IST 2014 errCode : -1 HeartBeat Message Sent Task 2:: 30 seconds completed :: Updating health status to AMBER Sending HeartBeat Message status: AMBER timeOfHeartBeat: Mon Jun 16 23:52:34 IST 2014 errCode : -1 HeartBeat Message Sent Sending HeartBeat Message status: AMBER timeOfHeartBeat: Mon Jun 16 23:52:44 IST 2014 errCode : -1 HeartBeat Message Sent Sending HeartBeat Message status: AMBER timeOfHeartBeat: Mon Jun 16 23:52:54 IST 2014 errCode : -1 HeartBeat Message Sent Cancelling Timer Cleanly after 60 seconds
As seen from output above, the Timer
is cancelled using the cancel
method which ensures that any TimerTask
being executed is completed before the Timer
is cleaned up.
Other Points about Timer
- The
Timer
instance created can be instructed to start theTaskThread
as a Daemon Thread, in case the thread should no longer exist if there are no non-daemon threads remaining in the VM. - The
Timer
is thread-safe and is internally synchronized. - Java 5.0 introduced the
ScheduledThreadPoolExecutor
which is a thread pool for repeatedly executing tasks at a given rate or delay. It allows multiple service threads and accepts various time units. Thus, as theTimer
has one single task execution thread (highlighted above), theScheduledThreadPoolExecutor
can have multiple threads executing/dedicated to task execution, in turn preventing one faulty task causing other tasks to be waiting for thread resource for execution.
The source code is available for download here.