Is EntityManager really thread-safe?

For Application-Managed Entity Managers:

EntityManager instances are not thread-safe.

EntityManagerFactory instances are thread-safe.

Application-managed entity managers are used when applications need to access a persistence context that is not propagated with the JTA transaction across EntityManager instances in a particular persistence unit. In this case, each EntityManager creates a new, isolated persistence context. The EntityManager and its associated persistence context are created and destroyed explicitly by the application. They are also used when directly injecting EntityManager instances can’t be done because EntityManager instances are not thread-safe. EntityManagerFactory instances are thread-safe.

For more details visit here

For Container-Managed Entity Managers:

EntityManager is required to be safe to use within stateless session beans.


No, an EntityManager is NOT thread safe. Adam Bien though is also correct. You are just not looking at the question correctly. The question he is answering isn't if an EntityManager is thread safe, he is stating that using container managed EntityManger in a stateless session bean is safe, which it is. He then explains the reasoning and wording of the spec that allows the container to work its magic - "each instance sees only a serialized sequence of method calls". That allows container injection to have different EntityManager contexts per method invocation, similar to how each invocation can be tied to their own transaction and isolated resources.

Injection is really just injecting an EntityManager proxy that gives the container control over the lifecycle of the JPA EntityManagers underneath, allowing it to be tied to the thread and the transaction.

So an EntityManager is NOT thread safe, but the container injected EntityManager proxies are required to be safe to use within stateless session beans.


Although @Chris' answer helped me understand a bit more about EntityManager (thus the tick), I worked out the real problem - ManagedScheduledExecutorService does not necessarily auto-kill its threads on application termination - this appears to be true for Glassfish 4.0 also. So, although my underlying application had terminated, the thread still had an EntityManager from the dead app's EntityManagerFactory (I think), so when the timer ticked it spewed out the error I described above.

I fixed the problem by getting the ScheduledFuture and calling future.cancel(false) in my contextDestroyed().


Furthermore, it seems that Timer Tick beans and EntityManager don't mix, so I had to do this:

@Stateless
public class TimerTick implements TimerTickAbs, Runnable {
  @EJB private RealTimerTick realTick;
  @Override
  public void run() {
    realTick.run();
  }
  @Override
  public Runnable runner() {
    return this;
  }
}

and:

@Stateless
public class RealTimerTick implements TimerTickAbs, Runnable {
  @PersistenceContext private EntityManager entityManager;
  @Override
  public void run() {
    Query q = entityManager.createQuery("SELECT blah...");
  }
  @Override
  public Runnable runner() {
    return this;
  }
}

This now works perfectly, including automatic persistence of changes made to values returned from the Query, as far as I can tell, but I cannot explain it!