I am trying to achieve the following :
EJB3 Singleton
@Singleton
@Startup
public class SomeSingleton implements SomeSingletonLocal {
// Entity Manager injection
private EntityManager _entity_manager;
@Override
@Asynchronous
public void createScenario(){
method1();
method2();
// ...
}
public void method1(){
// Persist an Event in a Database.
}
public void method2(){
// Persist an Event in a Database.
}
}
Managed Bean
@ManagedBean
@RequestScoped
public class SomeManagedBean{
// Entity Manager injection
private EntityManager _entity_manager;
@EJB
private SomeSingletonRemote _singleton;
public void createScenario(){
_singleton.createScenario();
}
public List<Event> getEventList(){
// Retrieve events from database
}
}
JSF view
<h:form>
<p:commandButton value="Start Long Stuff"
actionListener="#{SomeManagedBean.createScenario}" />
<h:outputText id="count" value="#{SomeManagedBean.getEventList.size()}" />
<p:poll interval="1" update="count" />
</h:form>
log
->SomeManagedBean.getEventList()
<-SomeManagedBean.getEventList() // Size = 0// Buton clicked
->SomeManagedBean.createScenario()
->SomeSingleton.createScenario()
<-SomeManagedBean.createScenario()->SomeManagedBean.getEventList() // will end at the end of SomeSingleton.createScenario
->SomeSingleton.method1()
<-SomeSingleton.method1() // persist
...
->SomeSingleton.methodN()
<-SomeSingleton.methodN() // persist<-SomeSingleton.createScenario()
<-SomeManagedBean.getEventList() // size = N
I expected at least one call to getEventList between two methodI() call (ie. each second). When it enters in SomeSingleton.createScenario(), I dont know why getEventList is paused.
It looks like there is a lock with the entity manager or the transaction inside createScenario. Is that a reentrance problem ?
A @Singleton
is indeed by default read/write locked. This is not strictly related to transactions, but to concurrency. See also a.o. Java EE 7 tutorial on the subject.
One way to solve it is to set the @ConcurrencyManagement
to BEAN
. This way you basically tell the container to not worry about concurrency at all and that you take all responsibility on your own.
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class SomeSingleton {}
Another way is to explicitly set @Lock
to READ
on the class or the read-only methods so that they can concurrently be invoked. Only when a method with an explicit @Lock(LockType.WRITE)
is invoked on the same instance, then the lock will occur.
@Singleton
@Lock(LockType.READ)
public class SomeSingleton {}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With