Java Timer
0 CommentsLast Updated on June 30, 2019 by Simanta
Timer is a utility class as a facility for Threads to schedule tasks for future execution as a background thread. You can use this class to schedule tasks for one-time execution or for repeated execution at a regular interval.
In this post, I’ll explain how to schedule tasks in Java applications using the Timer and TimerTask classes.
Timer and TimerTask
Timer
is used with TimerTask
, an abstract class which defines the task to be scheduled by Timer
. You need to extend TimerTask
to create a task that will be scheduled by Timer
. Java TimerTask
implements the Runnable
interface.
Each of the TimerTask
is executed sequentially by a Timer
object which has a corresponding single background thread. TimerTask
objects should complete execution quickly. If a timer task takes too long to complete, it dominates the timer’s task execution thread, which in turn will delay the execution of the subsequent tasks. The tasks will finally accumulate into a queue.
Note: Java Timer
object can be shared by multiple threads without any external synchronization.
A TimerTask
object remains in one of the following states.
VIRGIN
: When a task is created, its initial state will beVIRGIN
SCHEDULED
: Once the task is picked up byTimer
for execution, its state is changed toSCHEDULED
.EXECUTED
: After execution its state becomesEXECUTED
.CANCELLED
: If we call thecancel()
method on a task, the task goes into theCANCELLED
state. A task in theCANCELLED
state will never be picked up by theTimer
for execution.
Scheduling Tasks with Timer
Let’s start coding and use Timer
to schedule a TimerTask
.
MyTask
is a Java class that defines its own task by extending TimerTask
.
MyTask.java
package springframework.guru.javatimer.task; import java.util.Date; import java.util.TimerTask; public class MyTask extends TimerTask { @Override public void run() { System.out.println("Start of mytask at " + new Date()); timeConsumingTask(); System.out.println("End of mytask at " + new Date()); } public void timeConsumingTask() { try { Thread.sleep(20000); }catch (InterruptedException ex) { ex.printStackTrace(); } } }
To define your own TimerTask
you need to override the run()
method of TimerTask
. Here we have assumed that the task will take 20 seconds to complete.
Next we will schedule the defined task.
Scheduling a Task to Run Once
I have written a JUnit test class to run the task we defined with the help of Timer
. If you are new to JUnit, I suggest going through my series of JUnit posts.
The MyTaskTest
class is this.
MyTaskTest.java
package springframework.guru.javatimer.task; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.util.Date; import java.util.Timer; public class MyTaskTest { MyTask myTask; Timer timer; @Before public void setUp() { myTask = new MyTask(); timer = new Timer(true); } @After public void tearDown() { myTask = null; timer = null; } @Test public void schedulingTaskOnce() { long delay = 1000L; timer.schedule(myTask, delay*10); System.out.println("MyTask begins!!" + new Date()); try { Thread.sleep(60000); } catch (InterruptedException e) { e.printStackTrace(); } } }
In the @Setup
method, Timer(true)
creates a new Timer
whose associated thread can be run as a daemon thread. You can also use the overladed Timer(String name)
constructor to create a timer whose thread has the specified name.
In the test case, the timer.schedule()
method schedules the TimerTask
to execute after a delay of 10,000
ms.
Once the timer schedules the task, the code instructs the timer’s thread to sleep for 60
seconds.
The output on running the tests in IntelliJ is this.
Scheduling a Repeated Task on a Regular Interval
You can use the scheduleAtFixedRate()
method of Timer
to schedule the TimerTask
periodically with a specific interval.
This code snippet schedules the task with a delay of 1000
ms and to repeat after every 500
ms.
@Test public void schedulingTaskAtRepeatedInterval() { long delay = 1000L; long period = 1000L; timer.scheduleAtFixedRate(myTask, delay, period); System.out.println("MyTask begins and repeats at a specific interval!!" + new Date()); try { Thread.sleep(60000); } catch (InterruptedException e) { e.printStackTrace(); } }
The output on running the tests in IntelliJ is this.
Scheduling a Task to Run Once a Day
Consider you need to schedule a task to run once a day. One approach is to call the scheduleAtFixedRate()
method passing the appropriate delay and period parameters like this.
@Test public void schedulingTaskDaily() { long delay = 1000L; long period = 1000L * 60L * 60L * 24L; timer.scheduleAtFixedRate(myTask, delay, period); System.out.println("MyTask begins and repeats every day!!" + new Date()); try { Thread.sleep(30000); } catch (InterruptedException e) { e.printStackTrace(); } }
The output on running the test in IntelliJ is this.
Another approach is to use the Timer.schedule(TimerTask task, Date firstTime, long period)
method.
Cancelling Timer and TimerTask
At times you might need to cancel a running TimerTask
. One way is to invoke the cancel()
method on the timer. The second way is to call the cancel()
method on the thread that runs the TimerTask
.
Call cancel()
on the Timer
if that’s all it is doing. On the other hand, if the timer itself has other tasks which you wish to continue, call the cancel()
method on the thread running TimerTask
like this.
public void run() { System.out.println("Start of mytask at " + new Date()); timeConsumingTask(); System.out.println("End of mytask at " + new Date()); cancel(); }
The test code is this:
@Test public void checkCancelOfTimerTask() { long delay = 1000L; long period = 1000L; timer.scheduleAtFixedRate(myTask, delay, period); System.out.println("MyTask begins and repeats at a specific interval and then cancels!!" + new Date()); try { Thread.sleep(60000); } catch (InterruptedException e) { e.printStackTrace(); } }
The output on running the tests in IntelliJ is this.
Note that when you call the cancel()
method within the run()
method of a TimerTask
that was invoked by this Timer
, it guarantees that the ongoing task will be the last task executed by the Timer
. It takes a minute and above to terminate the test since we have given 60
seconds to stop the Timer
thread.
On the other hand, the cancel()
method on Timer
terminates the timer discarding any currently scheduled tasks. The executing thread terminates once the timer is terminated and no more tasks can be scheduled on the cancelled timer.
The test code for calling cancel()
on the Timer
is this.
@Test public void checkCancelOnTimerObject() { long delay = 1000L; long period = 1000L; timer.scheduleAtFixedRate(myTask, delay, period); System.out.println("MyTask begins and repeats at a specific interval!!" + new Date()); try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } timer.cancel(); System.out.println("Timer cancelled"); }
Here we specify the sleep time for the Timer
thread because we are running the code snippet as a JUnit test case. Hence we must call Thread.Sleep(delay*n)
to allow the Timer’s thread to run the task before the JUnit test stops executing.
Let us change the sleep time of MyTask
to 1
second to check if the timer is cancelled.
public void timeConsumingTask() { try { Thread.sleep(1000); }catch (InterruptedException ex) { ex.printStackTrace(); } }
The output on running the tests in IntelliJ is this.
Summary
The built-in Timer is adequate for scheduling tasks in small to mid-size Java applications. When you are developing Spring applications, you can also use the TaskExecutor
and TaskScheduler
interfaces that the Spring Framework brings in.
However, for large-scale enterprise application development using Spring Boot, you need a more comprehensive scheduling solution.
Quartz is one open source job scheduling library with rich enterprise-class features including JTA transactions and clustering. Spring Boot provides the spring-boot-starter-quartz
“Starter” to get you quickly up and running with Quartz.