.
Developer Spot - Web Development Tutorials
arrowDeverloper Spot  Tutorials  JAVA  Scheduling Recurring Tasks In Java Applications 
 
Development Tutorials
ASP
CGI & Perl
CSS
HTML
Java
JavaScript
Linux
PHP
XML




More Resources
Web Hosting Articles
Web Development News
PHP Manual
Web Hosting Directory
Budget Web Hosting Linux Web Hosting Small Business Hosting
Windows Web Hosting Reseller Web Hosting Web Hosting Articles

Scheduling Recurring Tasks In Java Applications

By Tom White
2004-01-23
Reader Rating: 5 out of 5
Bookmark Print Version
Real-time guarantees

When writing applications that use scheduling, it is important to understand what the framework promises in terms of timeliness. Will my tasks be executed early or late? If so, what's the maximum margin of error? Unfortunately, there are no simple answers to these questions. However, in practice the behavior is good enough for a large class of applications. The discussion below assumes that the system clock is correct (see Resources for information on the Network Time Protocol).

Because Scheduler delegates its scheduling to the Timer class, the real-time guarantees that Scheduler can make are identical to those of Timer. Timer schedules tasks using the Object.wait(long) method. The current thread is made to wait until it is woken up, which can happen for one of these reasons:

1. The notify() or notifyAll() method is called on the object by another thread.
2. The thread is interrupted by another thread.
3. The thread is woken up in the absence of a notify (known as a spurious wakeup, described in Item 50 of Joshua Bloch's Effective Java Programming Language Guide -- see Resources).
4. The specified amount of time has elapsed.

The first possibility cannot occur for the Timer class because the object that wait() is called on is private. Even so, the implementation of Timer safeguards against the first three causes of early wakeup, thus ensuring that the thread wakes up after the time has elapsed. Now, the documentation comment for Object.wait(long) states it may wake up after the time has elapsed "more or less", so it is possible that the thread wakes up early. In this case, Timer issues another wait() for (scheduledExecutionTime - System.currentTimeMillis()) milliseconds, thereby guaranteeing that tasks can never be executed early.

Can tasks be executed late? Yes. There are two main causes of late execution: thread scheduling and garbage collection.

The Java language specification is purposefully vague on thread scheduling. This is because the Java platform is general purpose and targets a wide range of hardware and associated operating systems. While most JVM implementations have a thread scheduler that is fair, it is by no means guaranteed -- certainly implementations have different strategies for allocating processor time to threads. Therefore, when a Timer thread wakes up after its allotted time, the time at which it actually executes its task depends on the JVM's thread scheduling policy, as well as how many other threads are contending for processor time. Therefore, to mitigate late task execution, you should minimize the number of runnable threads in your application. It is worth considering running schedulers in a separate JVM to achieve this.

The time that the JVM spends performing garbage collection (GC) can be significant for large applications that create lots of objects. By default, when GC occurs the whole application must wait for it to finish, which may take several seconds or more. (The command line option -verbose:gc for the java application launcher will cause each GC event to be reported to the console.) To minimize pauses due to GC, which may hinder prompt task execution, you should minimize the number of objects your application creates. Again, this is helped by running your scheduling code in a separate JVM. Also, there are a number of tuning options that you can try to minimize GC pauses. For instance, incremental GC attempts to spread the cost of the major collections over several minor collections. The trade-off is that this reduces the efficiency of GC, but this might be an acceptable price for timelier scheduling. (See Resources for more GC tuning hints.)

When was I scheduled?
To determine whether tasks are being run in a timely manner, it helps if the tasks themselves monitor and record any instances of late execution. SchedulerTask, like TimerTask, has a scheduledExecutionTime() method that returns the time that the most recent execution of this task was scheduled to occur. Evaluating the expression System.currentTimeMillis() - scheduledExecutionTime() at the beginning of the task's run() method lets you determine how late the task was executed, in milliseconds. This value could be logged to produce statistics on the distribution of late execution. The value might also be used to decide what action the task should take -- for example, if the task is too late, it might do nothing. If, after following the guidelines above, your application requires stricter guarantees of timeliness, consider looking at the Real-time Specification for Java (see Resources for more information).


Article Pages:
Introduction
Scheduling a one-shot task
Scheduling a recurring task
Implementing the scheduling framework
Extending the cron facility
Real-time guarantees
Conclusion
Resources

First published by IBM developerWorks


 Rate this article:   Poor          Excellent 


If you found this article interesting, you may want to read these as well:

» Build and Implement A Single Sign-On Solution

» Eye On Performance: A Load Of Stress

» A Brief History Of Garbage Collection



 
Development Tutorials: CGI & Perl - CSS - HTML - Java - JavaScript - Linux - PHP - XML
More Resources: Web Hosting Articles - Web Development News - PHP Manual