Friday, October 23, 2009

Adjustable Timer Task

Java provides TimerTask for tasks that can be scheduled for one-time or repeated execution by a Timer. But it has some serious drawbacks.

First, TimerTask can only be scheduled either for one-time or for repeated execution of a roughly fixed period. It can not be scheduled with changing periods, for example, at the following moments since its start: 0, 5, 6, 12, 100, 101, 102 seconds ... If it is scheduled twice, for example, first scheduled after 1 seconds, then 3 seconds after the first execution, no matter in which thread the second schedule is requested, inside or outside the Timer thread, a java.lang.IllegalStateException: Task already scheduled or cancelled will be thrown.

Second, each TimerTask is served with an individual background thread. Thus it makes TimerTask not a very scalable solution if a lot of TimerTasks are needed but each of them is not very heavy weighted.

Since 1.5, Java provides the java.util.concurrent package, which includes an Executor Framework. The basic idea of Executor Framework is to separate the concerns of tasks and the mechanism to execute tasks. So programmers define tasks and then leave tasks to be executed by the Executor Framework, which can be configurable to use a single thread, or a thread pool to execute the tasks.

The following Java code illustrates how to use ScheduledExecutorService to implement adjustable timer task.


public class Test {

static private ScheduledExecutorService scheduler =
Executors.newSingleThreadScheduledExecutor();

static private Runnable pig = new Runnable() {
public void run() {
System.out.println("This is pig");
scheduler.schedule(this, 1,
TimeUnit.SECONDS);
};
};

static private Runnable bear = new Runnable() {
Random random = new Random();
public void run() {
System.out.println("This is bear");
scheduler.schedule(this,
2 + random.nextInt(3),
TimeUnit.SECONDS);
};
};

/**
* @param args
*/
public static void main(String[] args) {
scheduler.schedule(pig, 0, TimeUnit.SECONDS);
scheduler.schedule(bear, 0, TimeUnit.SECONDS);
}

}

No comments: