Java EE EJB concurrency (ConcurrencyManagement, Lock and LockType)

31 May 2015
By Gonçalo Marques
This article will cover EJB concurrent access configuration (both container and bean managed) resorting to Lock, LockType and ConcurrencyManagement primitives.

Stateless EJB's

Even though Stateless EJB's may never be concurrently accessed by more than a single client call, this article would be otherwise incomplete if it did not mention this kind of EJB's.

Stateless EJB's are pooled by the container. Every time a client makes a call to a Stateless EJB, the container will fetch an available instance from the pool to handle the client request. When that instance is handling the client request, that same instance will not handle any other call that is made from any given client. When that call ends, the EJB instance is returned to the pool and becomes once again available to handle client requests.

If there is no available EJB instance in the pool to handle a client request (ex: the pooled EJB instances are all busy handling other requests), the container will create a new instance, put it in the pool, and let it handle the incoming client request.

This pool is usually configured by application server, and if it becomes exhausted when a client request arrives (ex: the pool has reached its maximum size) an exception will be thrown and propagated to the remote client.

Even if there are multiple consecutive calls from the same client to the same Stateless EJB, it should never be assumed that those consecutive calls will be handled by the same EJB instance.

Stateless EJB

@Stateless
public class StatelessEJB {

  public void doSomething(){

  }

}


EJB client

@EJB
private StatelessEJB statelessEJB;

public void clientMethod() {

  // These consecutive calls are NOT guaranteed to
  // be handled by the same Stateless EJB instance
  statelessEJB.doSomething();
  statelessEJB.doSomething();

}

Container managed concurrency

As opposed to Stateless EJB's, Singleton and Stateful EJB's may be configured to handle concurrent requests from any given client.

Container managed concurrency configuration applies both to Singleton and Stateful EJB's - keep in mind that Stateful EJB's concurrency strategy will always consist in WRITE (exclusive) locking semantics. It allows, in conjunction with Lock and LockType primitives, to configure how concurrent access should be allowed by the container while handling EJB calls, with method level granularity:

Singleton EJB

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class SingletonEJB {

  int counter;

  @Lock(LockType.READ)
  public int readCounter() {
    return counter;
  }

  @Lock(LockType.WRITE)
  public void incrementCounter() {
    counter++;
  }

}

By default, every Stateful and Singleton EJB has container managed concurrency so, in this example, the annotation @ConcurrencyManagement with its value defined as CONTAINER is redundant.


Note: Stateful EJB's container managed concurrency will always have WRITE locking semantics. READ locking semantics apply only to Singleton EJB's.

The Lock annotation may have a couple of distinct values: READ and WRITE. Methods annotated with READ lock type may be accessed concurrently by any arbitrary number of clients, given the fact that there is no method configured with WRITE lock type being accessed at that moment.

WRITE lock type methods are exclusive, ie. if a WRITE locked method is being accessed at a given moment, no other method - READ or WRITE - may be accessed until the method execution completes. Since WRITE methods are exclusive, if a WRITE method is ready to be executed but there is(are) other method(s) executing at that time, it must wait for the them to complete in order to acquire the exclusive lock and proceed.

It's important to mention that the Lock annotation may also be defined at class level, meaning that the specified access type will then be applied to all EJB methods. We may override the behavior for specific methods by applying the annotation to a given method:

Singleton EJB (Lock configuration at class level)

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@Lock(LockType.READ)
public class SingletonEJB {

  int counter;
  
  // This method will inherit the Lock 
  // configuration defined at class level
  public int readCounter() {
    return counter;
  }

  // This method overrides the class level
  // Lock semantics by changing it to WRITE
  @Lock(LockType.WRITE)
  public void incrementCounter() {
    counter++;
  }

}

Note: By default, every Singleton EJB has container managed concurrency with WRITE lock semantics for all methods. You really should take a look into your EJB's and see if this is in fact the desired behavior. If you have methods that, for example, should be allowed to execute concurrently because they do not modify the EJB instance state, maybe you could configure them with READ lock semantics (otherwise you end up with a serialized access bottleneck even in read operations).

We end this section mentioning the access timeout configuration. One may additionally configure the amount of time that a client request will wait for concurrent method access, before giving up. Once the timeout is reached, the container will throw an exception which will be propagated to the calling client. The timeout is configured by the @AccessTimeout annotation, which may be defined at both class and method level (the method level configuration overrides the class level configuration):

AccessTimeout configuration

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@AccessTimeout(value = 5000)
public class SingletonEJB {

  int counter;

  @Lock(LockType.READ)
  @AccessTimeout(value = 2, unit = TimeUnit.SECONDS)
  public int readCounter() {
    return counter;
  }

  @Lock(LockType.WRITE)
  public void incrementCounter() {
    counter++;
  }

}

The Access Timeout annotation may be configured with value and unit properties: the value property specifies the amount of time before the timeout is reached, while the unit - as the name states - specifies the unit in which the time property value is defined. The default time unit is MILLISECONDS.

In this example, the incrementCounter() method will have a timeout of 5 seconds (inherited from the class level configuration), while the method readCounter() will have a timeout of 2 seconds (overriding the class level configuration).

Bean managed concurrency

As the ConcurrencyManagement documentation states, bean managed concurrency is only applied to Singleton EJB's.

Bean managed concurrency is defined like the following:

Bean managed concurrency Singleton EJB

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class SingletonEJB {

  public void someMethod() {

  }

}

Bean managed concurrency means that no Java EE primitives, like Lock and LockType, may be used to manage concurrent access to a given Singleton EJB. The application is instead responsible to manage concurrent access by the means of the traditional concurrent access primitives, like synchronized, volatile, wait, notify or any other data structure or library that provides concurrent access management.

Related Articles

Comments

About the author
Gonçalo Marques is a Software Engineer with several years of experience in software development and architecture definition. During this period his main focus was delivering software solutions in banking, telecommunications and governmental areas. He created the Bytes Lounge website with one ultimate goal: share his knowledge with the software development community. His main area of expertise is Java and open source.

GitHub profile: https://github.com/gonmarques

He is also the author of the WiFi File Browser Android application: