29-03-2012, 01:27 PM
Scheduling and Thread Pooling
23.1. Introduction
The Spring Framework features integration classes for scheduling support. Currently, Spring supports the
Timer, part of the JDK since 1.3, and the Quartz Scheduler Both
schedulers are set up using a FactoryBean with optional references to Timer or Trigger instances, respectively.
Furthermore, a convenience class for both the Quartz Scheduler and the Timer is available that allows you to
invoke a method of an existing target object (analogous to the normal MethodInvokingFactoryBean operation).
Spring also features classes for thread pooling that abstract away differences between Java SE 1.4, Java SE 5
and Java EE environments.
23.2. Using the OpenSymphony Quartz Scheduler
Quartz uses Trigger, Job and JobDetail objects to realize scheduling of all kinds of jobs. For the basic
concepts behind Quartz, have a look at For convenience purposes,
Spring offers a couple of classes that simplify the usage of Quartz within Spring-based applications.
23.2.1. Using the JobDetailBean
JobDetail objects contain all information needed to run a job. The Spring Framework provides a
JobDetailBean that makes the JobDetail more of an actual JavaBean with sensible defaults. Let's have a look
at an example:
The job detail bean has all information it needs to run the job (ExampleJob). The timeout is specified in the job
data map. The job data map is available through the JobExecutionContext (passed to you at execution time),
but the JobDetailBean also maps the properties from the job data map to properties of the actual job. So in this
case, if the ExampleJob contains a property named timeout, the JobDetailBean will automatically apply it:
package example;
Spring Framework (2.5.6) 498
All additional settings from the job detail bean are of course available to you as well.
Note: Using the name and group properties, you can modify the name and the group of the job, respectively. By
default, the name of the job matches the bean name of the job detail bean (in the example above, this is
exampleJob).
23.2.2. Using the MethodInvokingJobDetailFactoryBean
Often you just need to invoke a method on a specific object. Using the MethodInvokingJobDetailFactoryBean
you can do exactly this:
The above example will result in the doIt method being called on the exampleBusinessObject method (see
below):
Using the MethodInvokingJobDetailFactoryBean, you don't need to create one-line jobs that just invoke a
method, and you only need to create the actual business object and wire up the detail object.
By default, Quartz Jobs are stateless, resulting in the possibility of jobs interfering with each other. If you
specify two triggers for the same JobDetail, it might be possible that before the first job has finished, the
second one will start. If JobDetail classes implement the Stateful interface, this won't happen. The second
job will not start before the first one has finished. To make jobs resulting from the
MethodInvokingJobDetailFactoryBean non-concurrent, set the concurrent flag to false.
23.2.3. Wiring up jobs using triggers and the Scheduler
FactoryBean
We've created job details and jobs. We've also reviewed the convenience bean that allows to you invoke a
method on a specific object. Of course, we still need to schedule the jobs themselves. This is done using
Scheduling and Thread Pooling
Spring Framework (2.5.6) 499
triggers and a SchedulerFactoryBean. Several triggers are available within Quartz. Spring offers two
subclassed triggers with convenient defaults: CronTriggerBean and SimpleTriggerBean.
Triggers need to be scheduled. Spring offers a SchedulerFactoryBean that exposes triggers to be set as
properties. SchedulerFactoryBean schedules the actual jobs with those triggers.
Find below a couple of examples:
Now we've set up two triggers, one running every 50 seconds with a starting delay of 10 seconds and one every
morning at 6 AM. To finalize everything, we need to set up the SchedulerFactoryBean:
More properties are available for the SchedulerFactoryBean for you to set, such as the calendars used by the
job details, properties to customize Quartz with, etc. Have a look at the SchedulerFactoryBean Javadoc for
more information.
23.3. Using JDK Timer support
The other way to schedule jobs in Spring is to use JDK Timer objects. You can create custom timers or use the
timer that invokes methods. Wiring timers is done using the TimerFactoryBean.
23.3.1. Creating custom timers
Using the TimerTask you can create customer timer tasks, similar to Quartz jobs:
public class CheckEmailAddresses extends TimerTask {
private List emailAddresses;
public void setEmailAddresses(List emailAddresses) {
this.emailAddresses = emailAddresses;
}
public void run() {
// iterate over all email addresses and archive them
}
}
Scheduling and Thread Pooling
Spring Framework (2.5.6) 500
Wiring it up is simple:
Changing the timerTask reference of the ScheduledTimerTask example to the bean doIt will result in the doIt
method being executed on a fixed schedule.
23.3.3. Wrapping up: setting up the tasks using the TimerFactoryBean
The TimerFactoryBean is similar to the Quartz SchedulerFactoryBean in that it serves the same purpose:
setting up the actual scheduling. The TimerFactoryBean sets up an actual Timer and schedules the tasks it has
references to. You can specify whether or not daemon threads should be used.
Scheduling and Thread Pooling
Spring Framework (2.5.6) 501
23.4. The Spring TaskExecutor abstraction
23.4. The Spring TaskExecutor abstraction
Spring 2.0 introduces a new abstraction for dealing with executors. Executors are the Java 5 name for the
concept of thread pools. The "executor" naming is due to the fact that there is no guarantee that the underlying
implementation is actually a pool; an executor may be single-threaded or even synchronous. Spring's
abstraction hides implementation details between Java SE 1.4, Java SE 5 and Java EE environments.
Spring's TaskExecutor interface is identical to the java.util.concurrent.Executor interface. In fact, its
primary reason for existence is to abstract away the need for Java 5 when using thread pools. The interface has
a single method execute(Runnable task) that accepts a task for execution based on the semantics and
configuration of the thread pool.
The TaskExecutor was originally created to give other Spring components an abstraction for thread pooling
where needed. Components such as the ApplicationEventMulticaster, JMS's
AbstractMessageListenerContainer, and Quartz integration all use the TaskExecutor abstraction to pool
threads. However, if your beans need thread pooling behavior, it is possible to use this abstraction for your own
needs.
23.4.1. TaskExecutor types
There are a number of pre-built implementations of TaskExecutor included with the Spring distribution. In all
likelihood, you shouldn't ever need to implement your own.
• SimpleAsyncTaskExecutor
This implementation does not reuse any threads, rather it starts up a new thread for each invocation.
However, it does support a concurrency limit which will block any invocations that are over the limit until a
slot has been freed up. If you're looking for true pooling, keep scrolling further down the page.
• SyncTaskExecutor
This implementation doesn't execute invocations asynchronously. Instead, each invocation takes place in the
calling thread. It is primarily used in situations where mutlithreading isn't necessary such as simple test
cases.
• ConcurrentTaskExecutor
This implementation is a wrapper for a Java 5 java.util.concurrent.Executor. There is an alternative,
ThreadPoolTaskExecutor, that exposes the Executor configuration parameters as bean properties. It is rare
to need to use the ConcurrentTaskExecutor but if the ThreadPoolTaskExecutor isn't robust enough for your
needs, the ConcurrentTaskExecutor is an alternative.
• SimpleThreadPoolTaskExecutor
This implementation is actually a subclass of Quartz's SimpleThreadPool which listens to Spring's lifecycle
callbacks. This is typically used when you have a threadpool that may need to be shared by both Quartz and
non-Quartz components.
• ThreadPoolTaskExecutor
Scheduling and Thread Pooling
Spring Framework (2.5.6) 502
It is not possible to use any backport or alternate versions of the java.util.concurrent package with
this implementation. Both Doug Lea's and Dawid Kurzyniec's implementations use different package
structures which will prevent them from working correctly.
This implementation can only be used in a Java 5 environment but is also the most commonly used one in
that environment. It exposes bean properties for configuring a java.util.concurrent.ThreadPoolExecutor
and wraps it in a TaskExecutor. If you need something advanced such as a ScheduledThreadPoolExecutor,
it is recommended that you use a ConcurrentTaskExecutor instead.
• TimerTaskExecutor
This implementation uses a single TimerTask as its backing implementation. It's different from the
SyncTaskExecutor in that the method invocations are executed in a separate thread, although they are
synchronous in that thread.
• WorkManagerTaskExecutor
CommonJ is a set of specifications jointly developed between BEA and IBM. These specifications are not
Java EE standards, but are standard across BEA's and IBM's Application Server implementations.
This implementation uses the CommonJ WorkManager as its backing implementation and is the central
convenience class for setting up a CommonJ WorkManager reference in a Spring context. Similar to the
SimpleThreadPoolTaskExecutor, this class implements the WorkManager interface and therefore can be
used directly as a WorkManager as well.
23.4.2. Using a TaskExecutor
Spring's TaskExecutor implementations are used as simple JavaBeans. In the example below, we define a bean
that uses the ThreadPoolTaskExecutor to asynchronously print out a set of messages.
import org.springframework.core.task.TaskExecutor;
public class TaskExecutorExample {
private class MessagePrinterTask implements Runnable {
private String message;
public MessagePrinterTask(String message) {
this.message = message;
}
public void run() {
System.out.println(message);
}
}
private TaskExecutor taskExecutor;
public TaskExecutorExample(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
public void printMessages() {
for(int i = 0; i < 25; i++) {
taskExecutor.execute(new MessagePrinterTask("Message" + i));
Scheduling and Thread Pooling
Spring Framework (2.5.6) 503
}
}
}
As you can see, rather than retrieving a thread from the pool and executing yourself, you add your Runnable to
the queue and the TaskExecutor uses its internal rules to decide when the task gets executed.
To configure the rules that the TaskExecutor will use, simple bean properties have been exposed.