JBuildingBlocks Task Scheduler (JbbTaskScheduler)
>>
monitorit
>>
monitorit
>>
JbbCore
>>
JbbDate
>>
JbbTaskScheduler
Table of Contents
What is the JbbTaskScheduler?
JbbTaskScheduler is an
easy to use multi-threaded task scheduler that has been
optimized for high performance, scalability and reliability.
The JbbTaskScheduler main features are:
- Support for a wide range of applications:
From lightweight applications with a minimum set of tasks and schedules requirements to the most demanding
applications with a very large set of intensive I/O bound tasks
- Optimized and fine-tuned for high-performance and scalability
- Easy to integrate with any J2SE or J2EE application
- Support for one-time, N-time and repetitive (including variable rate) tasks
- Advanced and flexible scheduling API for both built-in and custom task schedules
- Extensive set of built-in task schedules:
- JbbSchedule
- JbbOneShotSchedule
- JbbNShotsSchedule
- JbbPeriodicSchedule
- JbbDaySchedule (which also handles business day only type of schedule)
- JbbWeekSchedule
- JbbMonthSchedule
- Extensive task submission and task completion API (the calling thread is never blocked):
- addOneShotTask(JbbTask,long)
- addNShotsTask(JbbTask,long,long,long)
- addPeriodicTask(JbbTask,long,long)
- addTask(JbbTask,JbbSchedule)
- getCompletedTasks()
- getCompletedTask(long taskId)
- Extensive administrative API:
- Large set of configuration parameters (all with default values) for optimal configuration
- Enable/disable the entire task scheduler
- Enable/disable a task
- Modify the schedule associated to a task
- Remove a task
- Force the immediate execution of a task
- Extensive statistics API:
- The following task scheduler statistics can be queried at any time:
The start time, the up time, the number of completed executions, the current number of active threads, the current number of threads, the largest number of threads and the maximum possible number of threads
- The following task statistics can be queried at any time for a given task:
The status, the next execution time, the elapsed time before the next execution, the current number of executions, the last delta (difference between the requested time and the actual execution time),the id and name of the task
- The list of current tasks can be queried at any time and the list contains the following information for each task:
The status, the next execution time, the elapsed time before the next execution, the current number of executions, the last delta (difference between the requested time and the actual execution time),the id and name of the task
- Intuitive and well documented set of API
Optimized for reliability
Optimized footprint: the entire JbbTaskScheduler is less than 200 KB
- Commercial support and professional services
JbbTaskScheduler is at the heart of several applications including our JAppMonitor product and MonitorIt solutions. Version 2 of the JbbTaskScheduler has executed more than 2 billions task and our current Version 3 that has just been released is already over the 1.5 million number of execution.
In a few simple words, it's rock solid, fast and scalable (and it doesn't consume too many of your CPU and system resources)...
Sample Usage
Instantiating and initializing the task scheduler:
The following code sample demonstrates how to create an instance of the JbbTaskScheduler class:
import com.quadrique.jbuildingblocks.taskScheduler.*;
...
// obtain a new instance (initialized with the
// default values for the configuration parameters)
JbbTaskScheduler ts = JbbTaskScheduler.newInstance();
// start it
ts.start();
Once your task scheduler has been initialized and started, it is time to add ... a task and its schedule!
Adding a task with a simple schedule:
For the task scheduler, a
task is simply an instance of a class that implements the following JbbTask interface:
/**
* This is the interface that must be implemented
* by any task submitted to the task scheduler.
*/
public interface JbbTask
{
/**
*
* @return the name of the task.
* Please note that the name doesn't have to be unique, it simply is
* a convenience method to add a user friendly name to a task.
*/
public String getName();
/**
*
* Once the desired execution time has been reached, this method will
* be called by the task scheduler to execute the task
*/
public abstract void execute(JbbContext context) throws Throwable;
}
Please note that your task can be any Java class, the only requirement is that the class has to implement those 2 simples primitives.
The following code sample demonstrates a sample task that does nothing else than displaying a message on the standard output:
package com.quadrique.jbuildingblocks.taskScheduler.tests;
import com.quadrique.jbuildingblocks.core.JbbFactory;
import com.quadrique.jbuildingblocks.core.time.JbbDate;
import com.quadrique.jbuildingblocks.taskScheduler.tasks.contexts.JbbContext;
import com.quadrique.jbuildingblocks.taskScheduler.tasks.tasks.JbbTask;
/**
* Simple task class
*/
public class JbbTestTask3 implements JbbTask
{
/**
*
*/
public String getName()
{
return "Simple task";
}
/**
*
*/
public void execute(JbbContext context) throws Throwable
{
StringBuffer s = new StringBuffer();
s.append("\nTask Id: ");
s.append(context.getId());
s.append("\nExecution Time: ");
JbbDate d = JbbFactory.newJbbDate(context.getCurrentTime());
s.append(d.formatDateTimeFull());
s.append("\nNumber of Execution: ");
s.append(context.getNbOfExecution());
System.out.println(s.toString());
}
}
The following code sample demonstrates how to execute the previous task three times in a row starting immediately and with a 5 seconds delay between each execution:
// get a new task scheduler instance and start it
JbbTaskScheduler ts = JbbTaskScheduler.newInstance();
ts.start();
// add the task
ts.addNShotsTask(new JbbTestTask3(),
System.currentTimeMillis(), // initial execution time
3, // number of times the task should be executed
5000); // 5 seconds interval between each execution
Here is the actual output of the previous code sample:
Task Id: 1
Execution Time: Friday, June 27, 2008 3:12:06 PM EDT
Number of Execution: 1
Task Id: 1
Execution Time: Friday, June 27, 2008 3:12:11 PM EDT
Number of Execution: 2
Task Id: 1
Execution Time: Friday, June 27, 2008 3:12:16 PM EDT
Number of Execution: 3
In addition to addNShotsTask(...), the task scheduler also provide the addOneShotTask(...) and addPeriodicTask(...) methods.
Those conveniences methods are intuitive and easy to use and they cover the corresponding simple (yet very common) type of schedules.
Adding a task with a complex schedule:
To handle the most complex type of schedules, the task scheduler uses a very advanced and flexible mechanism to define a schedule and to associate it to a task.
For the task scheduler, a
schedule is simply an instance of a class that implements the following JbbSchedule interface:
package com.quadrique.jbuildingblocks.taskScheduler.tasks.schedules;
import com.quadrique.jbuildingblocks.taskScheduler.tasks.contexts.JbbContext;
import com.quadrique.jbuildingblocks.taskScheduler.tasks.tasks.JbbTask;
/**
* This class defines the interface that each schedule must implement
*/
public interface JbbSchedule
{
/**
* @param the current time
* @return the initial execution time
* i.e the time at which the task should be executed for the first time
*/
public abstract long getInitialExecutionTime(long currentTime);
/**
*
* @param context the context that has just been used
* by the task during its execution
* @param task the task
* @return the next execution time or 0 if the task
* is completed and should not be executed anymore
*/
public abstract long getNextExecutionTime(JbbContext context,JbbTask task);
}
The interface has two purposes:
- It defines when the task should be executed for the first time
- Whenever the task has been executed, it defines if the task should be executed again and if so, at what time that execution should take place
This advanced and flexible mechanism allows you to specify any type of schedule (including variable/dynamic rate based on the result of your previous task execution...). You can either write your own custom schedule
or use one of the several built-in schedules that are provided with the task scheduler.
The association of the task with its schedule is done with the addTask(JbbTask,JbbSchedule) method as shown in the following sample code:
// get a new task scheduler instance and start it
JbbTaskScheduler ts = JbbTaskScheduler.newInstance();
ts.start();
// add the task
JbbNShotsSchedule schedule = new JbbNShotsSchedule(System.currentTimeMillis(),3,5000);
ts.addTask(new JbbTestTask3(),schedule);
The actual output of the previous code sample is shown below:
Task Id: 1
Execution Time: Friday, June 27, 2008 3:49:06 PM EDT
Number of Execution: 1
Task Id: 1
Execution Time: Friday, June 27, 2008 3:49:11 PM EDT
Number of Execution: 2
Task Id: 1
Execution Time: Friday, June 27, 2008 3:49:16 PM EDT
Number of Execution: 3
As you probably already noticed, the results are identical to the previous example results: it simply is another way to define a schedule and to associate it to a task.
Shutting down the task scheduler:
The following code sample demonstrates how to shutdown your JbbTaskScheduler instance:
// get a new task scheduler instance and start it
JbbTaskScheduler ts = JbbTaskScheduler.newInstance();
ts.start();
// add the task
JbbNShotsSchedule schedule = new JbbNShotsSchedule(System.currentTimeMillis(),3,5000);
ts.addTask(new JbbTestTask3(),schedule);
// wait the task completion
Thread.sleep(18000);
// shutdown the task scheduler
ts.shutdown();
Please note that there is another shutdown() method with a parameter that specifies the maximum amount of time the task scheduler should wait for its active tasks to terminate their processing.
Once that delay is expired, the task scheduler will terminate all the tasks that are still active: it will actually interrupt the tasks with
Thread.interrupt() but any task that fails to respond to interrupts may never terminate.
The default value is 5 seconds which is ample enough for the vast majority of short lived tasks.
JbbContext
We strongly encourage you to contact us for any questions/concerns you might have.
To avoid any concurrency issue, we recommend
, please do not forget that you are running in a multi-threaded enviroment
If you have multiple instances of the same task that might be executed
Built-in Schedules
Custom Schedules
Statistics Interface
JbbTaskInfo
JbbSchedulerInfo
Administrative Interface
enable/disable
remove
modify
Completed Tasks Interface
2 primitives...
Note, no listener...
Configuration Parameters
The following configuration parameters can be specified when you create an instance of the JbbTaskScheduler (there is a JbbTaskScheduler.newInstance(...) method that allows you to specify all those parameters):
- maxNbOfThreads:
The maximum number of threads that can be created in the main thread pool. The default value is 25.
- sleepTimeUnit and sleepTime:
The amount of time the task scheduler should wait before checking if a pending task is ready for execution. The default value is 10 milliseconds.
- threadsKeepAliveTime:
The amount of time (in number of milliseconds) for which threads may remain idle before being terminated. To maximize peformances (the task scheduler reuses threads to avoid the overhead incurred whenever a thread is created) and to minimize the amount of resources that it uses (any thread uses a substantial amount of synchronization/kernel/memory resources), the task scheduler dynamically maintains a pool of threads and this parameters specifies how quickly an idle thread should be terminated.
The default value is 30 seconds.
Please note that those parameters are only provided to meet the demands of high-end and intensive applications (we definitely have a few of those!) and that the default values are fine for the vast majority of lightweight applications.
Javadocs
Architecture and References
Preamble:We designed the task scheduler so that you (as an end user) are completely abstracted from all the underlying synchronization/threading/race conditions issues/subtleties (and potential headaches!).
Our goal is to provide you with the
most efficient and easy to use "turn-key" product.
Overal architecture (only for those of you who would like to get more details):In a nutshell, the task scheduler is a multi-threaded set of components. The key components are:
- The front-end (the JbbTaskScheduler class):
It is the sole interface to the outside world and it encapsulates all the underlying
subcomponents that are executed in separate threads (so that the calling application is never blocked)
- The main controller thread:
It provides the core logic and it dispatches the tasks to the various concurrent data collections
- The thread pool (and its associated input/output concurrent queues, thread factory and threads):
It is used to execute the tasks that are ready for execution
In terms of concurrent data collection, we are probably using most of the collections available in the concurrent package.
One of the key collection is the collection that holds the tasks that are waiting for their next execution time. We use a priority queue
that is based on a heap implementation and that provides the following performances:
- insert operations: lg N
- remove maximum: lg N
- remove: lg N
- find maximum: 1
- change priority: lg N
- joint: N
A substantial number of our performance optimizations actually came by reducing the overall need for synchronization and by using the most appropriate algorithms and collections in each case.
We also make extensive use of all the non-blocking primitives (peek() and poll() to name a few...).
References:For those of you who would like to know and learn more, we strongly recommend the following references:
Licensing
Alternatives
Prerequisites
We could have never reached the current level of performance and scalability without the state of the art
synchronization and threading primitives (fine-grained locks, condition variables...) that have been added to the Java JRE since version 5.0.
Version 5 of the JRE is therefore a requirement and as a general rule of thumb, we strongly recommend using the latest and greatest stable version (version 6 update 6 as the time of this writing).
The JbbTaskScheduler also requires the
JbbCore.jar primarily for the extensive date and time manipulation features offered by the JbbDate class.