Saturday, October 20, 2012

Timer vs ScheduledThreadPoolExecutor

Many time we come across scenarios, when we need a background thread to keep running and execute tasks at scheduled time. JDK provides java.util.Timer and java.util.concurrent.ScheduledThreadPoolExecutor for this purpose.

java.util.Timer
Timer was introduces in jdk 1.3. 
There is a single background thread for every Timer object that executes all the assigned timer's tasks We can create an instance of TimerTask(which implements runnable) and add it to Timer object. The Timer object will take care of running the TimerTask at scheduled time. Timer runs the tasks sequentially. So, if there are 4 tasks to be executed by the same Timer object at the same time, and any one of those task takes longer time, the other remaining tasks may get delayed. We should keep this in mind while designing our system.


code example:


import java.util.Timer;

public class TimerTest {

/**
* @param args
*/
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new MyTask(), 1000);
}

}

class MyTask extends java.util.TimerTask{
public void run(){
System.out.println("Time task is running");
}
}


In above code, I scheduled a task to run after 1000 milliseconds(1 second). 

A task can be scheduled for single or recurring execution. You can refer javadoc for various implementation of Timer.schedule() method.
Timer class also provides cancel() method to terminate any scheduled task.

Timer class internally maintains a queue and all the TimerTask objects are inserted inside that queue. The TimerTask object maintains different states : VIRGIN, SCHEDULED, EXECUTED, CANCELLED. When a task is created, its initial state will be VIRGIN. Once it gets picked up by Timer for execution, its state will be changed to SCHEDULED. After execution its state becomes EXECUTED. If we mark a Task status to CANCELLED (by calling cancel() method), then it will never be picked by the Timer for execution.

java.util.concurrent.ScheduledThreadPoolExecutor
You have seen above that in  case of Timer you have single working thread which executes multiple tasks sequentially. But it may not fulfill your purpose, if you want to have parallel execution or if you have long running tasks. 

ScheduledThreadExecutor provides multiple working threads by using Thread pool. This class extends ThreadPoolExecutor class and uses thread pool to have a pool of threads to execute multiple tasks in parallel.
It provides similar kind of scheduling methods as Timer. You can refer javadoc for method details.
ScheduledThreadPoolExecutor was introduced in JDK 1.5. 


Code example:


import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class
ScheduledThreadPoolExecutorTest
{

/**
* @param args
*/
public static void main(String[] args){
//creates thread pool of size 2
ScheduledThreadPoolExecutor threadPool = new ScheduledThreadPoolExecutor(2);
threadPool.schedule(new MyTask1(), 1, TimeUnit.SECONDS);
threadPool.schedule(new MyTask2(), 1, TimeUnit.SECONDS);
}

}
class MyTask1 implements Runnable
{
   public void run()
   {
      System.out.println("Task1 is running");
   }
}
class MyTask2 implements Runnable
{
   public void run()
   {
      System.out.println("Task2 is running");
   }
}


Above code runs MyTask1 and MyTask2 in parallel after 1 second with 2 threads in threadpool.

If you look at javadoc of ScheduledPoolExecutor, you can observe that it provides more richer implementation of methods than Timer.
It internally maintains java.util.concurrent.DelayQueue to keep all the runnable tasks. In DelayQueue, an object can be popped only when its delay has been expired.
You can also use Future and Callable using its submit() function, which will return Future representing the pending results of the task.
It provides shutDown() method to terminate the future executions, but the currently running task will be completed before shutdown.

In my opinion, one should go with ScheduledThreadPoolExecotor when multiple worker threads are required for parallel execution. Also when the requirement is complex and a richer infrastructure is required then ScheduledThreadPoolExecotor would be a good choice. For simple kind of implementation, Timer and TimerTask will be sufficient.

9 comments: