EJB 3.x : Lifecycle and Concurrency models (part 2)

Datetime:2016-08-23 02:00:21          Topic: EJB           Share

This is the second post of the two part series. Thefirst partcovered the life cycle and the concurrency behavior of Stateful and Stateless EJBs. I’ll cover  Singleton EJBs  in this post.

The Singleton pattern is arguably the most used (some times misused!) pattern out there.

Single-ton and loving it !

Single-ton and loving it !

Java EE frees us from writing explicit code (like one on the above picture) to implement the Singleton pattern. Singleton EJBs were introduced in EJB 3.1 which itself was part of Java EE 6 . All that’s required is a  @javax.ejb.Singleton

(class level) annotation (and a few more if you want to refine other aspects – read on) on a bean class to designate it as a Singleton session bean.

There is one and only one instance of a Singleton EJB in a JVM – no matter how many clients access it. Its not like Stateful SB –  one bean instance attached to a single client throughout its life cycle, neither like Stateless SB – a new instance for each client request.

What are the distinct states in the life cycle of a Singleton Session Bean?

The life cycle for Singleton beans is the same as Stateless session beans – in fact it is one of the simpler aspects of this bean type:

  • Does Not Exist
  • Ready

How do the states change? What triggers them?

Here is a quick tabular snap shot and a high level diagram . . .

Singleton Beans – State Transitions

Singleton Beans – State Transitions

State Transition Triggers Callbacks
DNE to R When the instance is first accessed via JNDI/DI or automatically instantiated by the container using the @Startup or @DependsOn @PostConstruct
R to DNE Container shuts down – destroys the bean instance or in case an Exception occurs in the @PostConstruct annotated method @PreDestroy

Note : DNE – Does Not Exist,  R – Ready

As stated earlier, life cycle is one of simpler features of Singleton beans. It’s critical to understand their concurrency aspects.

Singleton Session Beans: Concurrency Management

As stated – a Singleton has just one instance in the JVM. In a Java EE environment, concurrent access is inevitable – that’s why we are using a technology like Java EE in the first place ! One needs to make sure that the concurrency ( locking ) strategies w.r.t Singleton beans are well thought through, depending upon the use case and requirements.

Singleton – Consume With Care !

Singleton – Consume With Care !

Singleton bean concurrency can be divided into 2 major categories :

  • Container Managed (Default)
  • Bean Managed

Container Managed Concurrency

  • As the name suggests, the container applies sensible default configurations for the bean
  • Can be controlled using annotations as well as XML (deployment descriptors)
  • Explicitly declared using the @javax.ejb.ConcurrencyManagement annotation on the bean class itself
    • Default value is javax.ejb.ConcurrencyManagementType.CONTAINER
  • Two possible locking strategies provided by the container – applicable on both bean class or its individual methods
    • @javax.ejb.Lock with a value of javax.ejb.LockType.READ  – allows concurrent access given no write locks
    • @javax.ejb.Lock with a value of javax.ejb.LockType.WRITE ( Default ) – guarantees exclusive access – only a single thread can execute a bean method at a given point
  • @javax.ejb.AccessTimeout can be specified on a bean class or method to ensure that a thread does not block or hold a lock for an indefinite time span

Bean Managed Concurrency

  • The name clearly indicates – the concurrency aspects of the bean are left to the developer. Makes sense when finer concurrency control is required as compared to what’s been offered by the container via aforementioned constructs
  • Usage of appropriate Java concurrency constructs required e.g. synchronized, volatile etc
  • Hard to get right !

Code example

Let’s look into a simple code snippet in order to better make sense of the above stated facts:

Scenario one – Container managed concurrency (default, locking type not explicitly specified)

package com.abhirockzz.wordpress.ejb.lifecycle.singleton;

import com.abhirockzz.wordpress.ejb.lifecycle.stateful.MyStatefulBean;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Singleton
@Startup
public class MySingletonBean {

	public void act() {
		System.out.println("Entered MySingletonBean/act() on " + new Date().toString() + " . Singleton instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());
		try {
			Thread.sleep(2000);
		} catch (InterruptedException ex) {
			Logger.getLogger(MyStatefulBean.class.getName()).log(Level.SEVERE, null, ex);
		}

		System.out.println("Exit MySingletonBean/act() on " + new Date().toString() + " . Singleton instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());

	}
}
package com.abhirockzz.wordpress.ejb.lifecycle.singleton;

import java.io.IOException;
import java.util.Date;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "SingletonTestServlet", urlPatterns = {"/SingletonTestServlet"})
public class SingletonTestServlet extends HttpServlet {

	public SingletonTestServlet() {
	}

	@Inject
	MySingletonBean mySingleton;

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("Entered SingletonTestServlet/doGet() on " + new Date().toString() + " . Servlet instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());
		mySingleton.act();
	}

}

Using Apache JMeter – I fired 2 concurrent threads at SingletonTestServlet (yes, just two.. this is more of a demonstration, not a load testing competition!)

cmc-jmeter-1

cmc-jmeter-2

cmc-result

Observations

Looking at the logs, one can easily make out the following:

  • The Servlet of course is not thread safe, hence two threads enter at the same time
  • One of the threads enters the method in the Singleton bean class (marked in red) and further access is forbidden due to the  default WRITE lock type enforced by the container
  • As soon as the first thread finished execution, the second thread (marked in green) which was initially blocked, gets a chance to execute the Singleton bean method
  • Pretty simple!

Scenario two – Sticking with Container managed concurrency. Changing the explicit lock type from WRITE to READ

import com.abhirockzz.wordpress.ejb.lifecycle.stateful.MyStatefulBean;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class MySingletonBean {

	@Lock(LockType.READ)
	public void act() {
		System.out.println("Entered MySingletonBean/act() on " + new Date().toString() + " . Singleton instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());
		try {
			Thread.sleep(2000);
		} catch (InterruptedException ex) {
			Logger.getLogger(MyStatefulBean.class.getName()).log(Level.SEVERE, null, ex);
		}

		System.out.println("Exit MySingletonBean/act() on " + new Date().toString() + " . Singleton instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());

	}
}

What happens when the the application is bombarded (pun intended !) with 2 concurrent threads. . . ?

bmc-result

  • Two threads enter the Servlet at the same time – as expected
  • One of the threads enters the method in the Singleton bean class (marked in red)
  • The second thread (marked in green) also manages to enter the Singleton bean method at the same instant (check the time stamp)
  • Again – pretty simple!

Bean Managed concurrency is not something which I am depicting right now. As stated above, using BMC for a Singleton transfers the onus on to the developer and he is free to code concurrency features into the bean- this can be done simply using synchronized on each methods or other mechanisms e.g. from java.util.concurrent API.

Suggested Reading

Cheers !





About List