Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Leveraging EJB Timers for J2EE Concurrency

Improve the performance of your J2EE applications by using a concurrency approach that takes advantage of the inherent thread pool management of EJB timers.


advertisement
oncurrency is a well-known technique for improving the performance of many J2EE applications. For example, Web 2.0 mashup applications must aggregate data from multiple sources. Performing the aggregation in a single thread can result in high latency that degrades the end user experience. Concurrency can significantly improve performance by parallelizing the aggregation tasks. Similarly, concurrency can optimize computationally intensive operations and address performance bottlenecks in blocking I/O and network operations.

A number of approaches are available for concurrency in J2EE applications, but each has its shortcomings:

  • Explicit allocation of threads is discouraged by the J2EE specifications since containers handle thread management.
  • Using the Work Manager specification results in non-portable solutions that are limited to certain application servers, such as WebLogic and WebSphere, because it is not part of the J2EE specifications (including Java EE 5).
  • Encapsulating the work units in JMS queue messages that are then processed by Message Driven Beans (MDBs) in a concurrent fashion is appropriate for certain scenarios. However, this approach is relatively complex and resource-intensive for most applications.

This article introduces an alternative approach for J2EE concurrency that takes advantage of the inherent thread pool management of EJB timers. This approach is portable across application servers and does not require a messaging provider and resources such as queues and connection factories. Furthermore, since EJB timers are transactional and recoverable, this approach enables robust and reliable concurrency solutions.



The discussion begins with an overview of the EJB Timer-based concurrency API and goes on to present an example that demonstrates how to use the API. Then it delves into the details of the concurrency framework implementation and highlights factors you must consider when using this approach. The code presented is based on JDK 1.5 and EJB 3, and it was tested on JBoss 4.04GA (TimerConcurrencyEAR.ear). An EJB 2.1-based implementation (TimerConcurrencyEAR-EJB2_1.ear) is also provided in the code download.

EJB Timer-Based Concurrency API
To schedule tasks concurrently, you work with two main framework interfaces: Task and ConcurrencyManager. You need to implement the Task interface that follows to represent the work you plan to do:

public interface Task extends Runnable, Serializable { enum Status { Inactive, Started, Completed }; public void setStatus(Status status); public Status getStatus(); }

Task extends from Runnable, which encapsulates the work to be done in its run method. It also extends from java.io.Serializable to satisfy the recoverability requirement of EJB timers. The framework uses the status accessors to update the state of the task as it progresses through the execution lifecycle:

  1. Inactive, the initial state, indicates that execution has not yet begun.
  2. Started denotes that execution has started but not yet completed.
  3. Completed signifies that the task completed either successfully or unsuccessfully.

The class AbstractTask, provided for convenience, implements the status field accessors. Most of the time, you'll extend it as follows instead of implementing Task:

abstract public class AbstractTask implements Task { private Status status=Status.Inactive; public void setStatus(Status status) { this.status = status; } public Status getStatus(){ return status; } }

To schedule tasks for concurrent execution, you use the ConcurrencyManager interface like this:

public interface ConcurrencyManager { public void execute(Collection<Task> tasks); public void executeAndWait(Collection<Task> tasks); public Collection<Task> executeAndWait(Collection<Task> tasks, long timeout); }

The ConcurrencyManager provides three ways of scheduling tasks:

  • void execute(Collection<Task> tasks): This non-blocking method schedules the tasks for concurrent execution and returns immediately without waiting for completion.
  • void executeAndWait(Collection<Task> tasks): This blocking method schedules the tasks for concurrency execution and waits until all tasks are completed.
  • Collection<Task> executeAndWait(Collection<Task> tasks, long timeout): This method schedules tasks for concurrent execution and waits until all tasks are completed OR the timeout is exceeded, whichever comes first. It returns the set of completed tasks.

The various styles of concurrent execution offer flexibility in dealing with different application scenarios. The blocking style of scheduling is useful in applications where tasks have a relatively short time span and the client needs the results immediately. The non-blocking style is geared towards long-running tasks where the results are not needed immediately. In this case, tasks will often write results to the database to be later retrieved by another request.

The EJBTimerConcurrencyManager stateless session bean (SSB) provides the ConcurrencyManager implementation. An upcoming section covers it in detail.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap