Is in an EJB injected EntityManager thread-safe?

You can inject EntityManager directly into EJBs. But: is it thread safe?:

public class BookServiceBean implements BookService {

  @PersistenceContext EntityManager em;

  public void create(Book book) { this.em.persist(book);}


It is, the EJB 3.1 specification, JSR-318, page 82 explains the reasons:

"…The container serializes calls to each stateful and stateless session bean instance. Most containers will support many instances of a session bean executing concurrently; however, each instance sees only a serialized sequence of method calls. Therefore, a stateful or stateless session bean does not have to be coded as reentrant…"

"…The container must serialize all the container-invoked callbacks (that is, the business method interceptor methods, lifecycle callback interceptor methods, timeout callback methods, beforeCompletion, and so on), and it must serialize these callbacks with the client-invoked business method calls..."

Working with EJBs without any further configuration is thread-safe regardless whether you are invoking one method or multiple methods concurrently. The container cares about the serialization of calls.

Big thanks to Dean for this question!

NEW MUC Airport Workshop: Migrating Java Client (Swing / Java FX) to Web Standards

Airport MUC workshops: Web (SPA, PWAs, Offline, Desktop, Mobile) Applications Essentials and Effective Web Applications. No migrations. #usetheplatform

Podcast: and newsletter:

A book about rethinking Java EE Patterns


You might also explain _why_ it is that way.

For @Stateless EJBs it's a no-brainer anyway. Each thread will take a single instance from the EJB-Pool and returns it back to the pool if it's not needed anymore.

But what about injecting @PersistenceContext into a JSF managed bean or a Stateful Session bean?

In EE Servers an injected @PersistenceContext will _never_ give you a _native_ EntityManager but always only a 'Facade' or 'Proxy'. Internally this EntityManager-Facade might e.g. keep a ThreadLocal<EntityManager>. That's the reason why you can use the injected EntityManager in parallel: because you will just get different instances for each thread anyway.

Btw, this is exactly the reason why the EntityManager interfaces has a getDeletate() method. This will give you access to the 'native' EM...


Posted by struberg on June 25, 2012 at 05:15 PM CEST #

There's more to the story , however. If a SessionBean is also a Singleton then concurrency control comes back into play. From the spec mentioned above:

"It is legal to store Java EE objects that do not support concurrent access (e.g. Entity Managers, Stateful
Session Bean references) within Singleton bean instance state. However, it is the responsibility of the
Bean Developer to ensure such objects are not accessed by more than one thread at a time."

Posted by Dean Schulze on June 26, 2012 at 07:13 PM CEST #

@Struberg, You make it sound as if an injected EntityManager is actually thread-safe.

Is there a difference an injected EntityManager (class-level) and a local EntityManager obtained from and EntityManagerFactory? I know their lifecycle management will be different, but as far as thread-safety goes aren't they both not-thread-safe?

Posted by Dean Schulze on June 27, 2012 at 03:50 AM CEST #


Knowing that the App Server has its proxy for the "real", underlying EntityManager and it can e.g. wrap it in ThreadLocal, I wonder why this approach can't be applied to every usage of @PersistenceContext.

In other words, why can't we have always-thread-safe EntityManager obtained by @PersistenceContext injection which under the hood is achieved with ThreadLocal<EntityManager> for EVERY injection point (doesn't matter if its SLSB, SFSB, EJB Singleton, Servlet, CDI Bean, JSF Backing bean, etc.)?

What is the rationale behind the actual approach? Wouldn't it simplify things to have always-thread-safe EM?


Posted by Piotr Nowicki on June 28, 2012 at 08:44 PM CEST #

Hey guys,

Does this mean that this code snippet would be legit?

public class BookServiceBean implements BookService {

@PersistenceContext EntityManager em;

public List<Book> findAll(Date d1, Date d2) {
List<Book> books = Collections.synchronizedList(new ArrayList<>());
CompletableFuture<Void> f1 = CompletableFuture.runAsync(()-> {
books.addAll((List<Book>) em.createQuery("select b from Book b where date = :D1").getResultList());
CompletableFuture<Void> f2 = CompletableFuture.runAsync(()-> {
books.addAll(((List<Book>) em.createQuery("select b from Book b where date = :D2").getResultList()));
CompletableFuture<Void> future = CompletableFuture.allOf(f1, f2);
try {
} catch (InterruptedException | ExecutionException e) {
// do something...
return books;



Posted by Christian on January 13, 2018 at 12:02 AM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
Online Workshops
...the last 150 posts
...the last 10 comments