The Java EE 6 Tutorial

Container-Managed Concurrency

If a singleton uses container-managed concurrency, the EJB container controls client access to the business methods of the singleton. The javax.ejb.Lock annotation and a javax.ejb.LockType type are used to specify the access level of the singleton’s business methods or @Timeout methods.

Annotate a singleton’s business or timeout method with @Lock(READ) if the method can be concurrently accessed, or shared, with many clients. Annotate the business or timeout method with @Lock(WRITE) if the singleton session bean should be locked to other clients while a client is calling that method. Typically, the @Lock(WRITE) annotation is used when clients are modifying the state of the singleton.

Annotating a singleton class with @Lock specifies that all the business methods and any timeout methods of the singleton will use the specified lock type unless they explicitly set the lock type with a method-level @Lock annotation. If no @Lock annotation is present on the singleton class, the default lock type, @Lock(WRITE), is applied to all business and timeout methods.

The following example shows how to use the @ConcurrencyManagement, @Lock(READ), and @Lock(WRITE) annotations for a singleton that uses container-managed concurrency.

Although by default, singletons use container-managed concurrency, the @ConcurrencyManagement(CONTAINER) annotation may be added at the class level of the singleton to explicitly set the concurrency management type:

@ConcurrencyManagement(CONTAINER)
@Singleton
public class ExampleSingletonBean {
  private String state;

  @Lock(READ)
  public String getState() {
    return state;
  }

  @Lock(WRITE)
  public void setState(String newState) {
    state = newState;
  }
}

The getState method can be accessed by many clients at the same time because it is annotated with @Lock(READ). When the setState method is called, however, all the methods in ExampleSingletonBean will be locked to other clients because setState is annotated with @Lock(WRITE). This prevents two clients from attempting to simultaneously change the state variable of ExampleSingletonBean.

The getData and getStatus methods in the following singleton are of type READ, and the setStatus method is of type WRITE:

@Singleton
@Lock(READ)
public class SharedSingletonBean {
  private String data;
  private String status;

  public String getData() {
    return data;
  }

  public String getStatus() {
    return status;
  }

  @Lock(WRITE)
  public void setStatus(String newStatus) {
    status = newStatus;
  }
}

If a method is of locking type WRITE, client access to all the singleton’s methods is blocked until the current client finishes its method call or an access timeout occurs. When an access timeout occurs, the EJB container throws a javax.ejb.ConcurrentAccessTimeoutException. The javax.ejb.AccessTimeout annotation is used to specify the number of milliseconds before an access timeout occurs. If added at the class level of a singleton, @AccessTimeout specifies the access timeout value for all methods in the singleton unless a method explicitly overrides the default with its own @AccessTimeout annotation.

The @AccessTimeout annotation can be applied to both @Lock(READ) and @Lock(WRITE) methods. The @AccessTimeout annotation has one required element, value, and one optional element, unit. By default, the value is specified in milliseconds. To change the value unit, set unit to one of the java.util.concurrent.TimeUnit constants: NANOSECONDS, MICROSECONDS, MILLISECONDS, or SECONDS.

The following singleton has a default access timeout value of 120,000 milliseconds, or 2 minutes. The doTediousOperation method overrides the default access timeout and sets the value to 360,000 milliseconds, or 6 minutes.

@Singleton
@AccessTimeout(value=120000)
public class StatusSingletonBean {
  private String status;

  @Lock(WRITE)
  public void setStatus(String new Status) {
    status = newStatus;
  }

  @Lock(WRITE)
  @AccessTimeout(value=360000)
  public void doTediousOperation {
    ...
  }
}

The following singleton has a default access timeout value of 60 seconds, specified using the TimeUnit.SECONDS constant:

@Singleton
@AccessTimeout(value=60, timeUnit=SECONDS)
public class StatusSingletonBean { ... }