5

I can't understand how the EJB container manage thread-safety for @Stateless beans with instance variables. So I will give a simple example before explaining my concerns:

@Stateless
public class BeanTest{

@Inject
private String var;

private Connection connection;

@Resource(name = "jdbc/TestDB")
private DataSource dataSource;

public void modify() {
    var = "TestName";
}

@PostConstruct
public void initialize() {
    try {
        connection = dataSource.getConnection();
    } catch (SQLException sqle) {
        sqle.printStackTrace();
    }
}

@PreDestroy
public void cleanup() {
    try {
        connection.close();
        connection = null;
    } catch (SQLException sqle) {
        sqle.printStackTrace();
    }
}
}

Here is my questions, assuming that our container supports pooling:

1. Pooling vs Thread-safe:

User 1 used an instance of BeanTest and modified the var using the modify method, then he finished and the container put the instance of BeanTest in the managed pool. When User 2 tries to use the same bean for a request, he might get the same instance of BeanTest intially modified by User 1 (I understand that might get another instance too). So which state of the instance variable var he will find (default value which is null or "TestName")? if its the new modified one, do that mean that even @Stateless beans are not 100% thread-safe? So finnaly there is no container added -value regarding thread safety, as not using instance variable makes a bean thread safe even if it's not a @Stateless bean

2. Pooling vs @PreDestroy

If the bean is returned to the managed pool and not destroyed, do that mean that the @Predestroy method will not be called and in that case the connection will stay opened ? So, if we have 30 inctance of that bean in the pool, we may have 30 open connection that is not used, isn't that a performance issue? or this not how @Predestroy is working conbined with pooling? (using Connection is just an example, we may have other kind of ressource that we need to close in @Predestroy)

NB: This is not a real life example, so I'am not looking for an alternative solution, my concern is to understand the whole concept and how things are managed in the Application Server, what is happening under the hood

Tarik
  • 4,961
  • 3
  • 36
  • 67
  • Your worries are exactly why I have steered clear of EJB whenever I could. With Spring you wouldn't get such nonsense, ill-defined semantics. – Marko Topolnik Aug 26 '15 at 15:20
  • May be you should use `@Stateful` instead of `@Stateless`? – Bhesh Gurung Aug 26 '15 at 15:25
  • Also, you should get a connection whenever you need one, not when the ejb is initialized. – Bhesh Gurung Aug 26 '15 at 15:34
  • @BheshGurung thanks for your reply, but I want to understand why it's not thread-safe, I'm not looking for an alyternative as it's not a real life issue – Tarik Aug 26 '15 at 16:24
  • It's thread-safe actually. Why do you say that it's not thread-safe? It's not possible for a thread to get an instance if some other thread has already got it. – Bhesh Gurung Aug 26 '15 at 16:26
  • but when, the thread in question finished working with that instance, The Appserver will reuse it (by adding it to the pool), So if another thread requested the same bean the Appserver will return an instance from the pool, which may be the same instance we already modified! – Tarik Aug 26 '15 at 16:30
  • Related: http://stackoverflow.com/a/31639830 – BalusC Aug 26 '15 at 21:41

3 Answers3

2

1) The container guarantees Thread safety which means that a single thread can access a given SLSB at a time. It has nothing to do with guaranteeing that the state won't be changed. BTW having mutable state inside SLSB makes no sense at all.

2) You don't want to keep a connection during the lifetime of a SLSB because you're effectively preventing it from returning to the pool risking an exhaustion.

Franck
  • 1,754
  • 1
  • 13
  • 14
  • I didn't understand the second point, but you are right about the first one. However, what I understood is that even the container doesn't garantee the statelessness, but it's the developper by not using instance variables – Tarik Aug 27 '15 at 07:53
  • depending if the app server is pooling or not your SLSB instance, the PreDestroy method might not be called when returning to the pool. This means that the Connection is not returning to the Connection Pool. If you reach your MaxConnection then you might wait indefinitely when trying to acquire a new Connection. – Franck Aug 27 '15 at 14:27
  • Thanks Franck for your clarifications – Tarik Aug 27 '15 at 18:19
2

I think the Thread-Safety you are referring to is the non-reenterant clause

The Responsibilities of the Container Provider Enterprise JavaBeans 3.2, Final Release Session Bean Component Contract April 10, 2013 2:59 pm Oracle

4.10.13 Non-reentrant Instances The container must ensure that on ly one thread can be executing a st ateless or stateful session bean instance at any time. Therefore, statef ul and stateless session beans do not have to be coded as reentrant. One implication of this rule is that an application ca nnot make loopback calls to a stateless or stateful session bean instance

You could in a stateless session bean, ignore the EJB programming restrictions, create a bunch of threads and do something non-Thread safe. the container won't stop you. This may cause all sorts of errors due to thread management conflicts.

The container only promises that it will only allow 1 thread access to the stateless ejb at a time. (there are some different rules around singletons)

you are right, that if the instances are returned to a pool that the connections in your example could build up. because of course the been instance still exists.

If you dig in to app server docs, ie Glassfish EJB pool tuning chapter, you will find that the default is to destroy the object instances rather than return them to the pool. same with the JDBC connections, which would get closed and cleaned up. Re-use is an option, in which case you could consume some extra memory if you attempt to create state in SSBs. I don't think there is much performance impact if the instance is sitting idle in a pool.

the exact pooling implementation is up to the application server vendor, so long as they obey the spec. I think you will find the default behavior is to destroy the instance after use. Which causes managed resources to get cleaned up.

But all this is kind of mute, in your example you are trying to store a state, the connection field, in the class. There is no need to create state in a stateless component, that is not what this type of component is for. Other parts of the Java EE architecture handle state. (entities, statefulbeans, JCA)

Chris
  • 194
  • 6
  • thanks for your axplanation. So to resume, the annotation `@Stateless` has no effect on making the bean stateless (I know that it has other effects: managed by the container, make use of services like transaction...) ? It's finnaly the developper who make design it stateless by not using instance variables... – Tarik Aug 27 '15 at 07:50
  • yes, @Stateless is how you tell the application server, its a stateless bean. the application server trusts that what ever you have written is really what you want to do. – Chris Aug 27 '15 at 14:24
1
  1. If the injected AnotherBean is stateless, then it makes no sense to call AnotherBean.setName(). If it is statefull, then it does not make sense to inject a stateful bean in a stateless one (check what stateful beans are made for). About thread-safety: the container cannot make your classes thread safe themself, but it guarantees that a single client thread will use a certain EJB instance at a time (check the quotation from Chris' answer). So, if you do not use an EJB in different threads in your EJB client, then your code is thread-safe by using thread confinment.
  2. Do not use instance variables other then injected ones in a stateless bean. Otherwise you are not consistent with your @Stateful annotation. So, remove the connection state variable. Anyway, you do not want to keep an open connection for long only for your bean: get it every time from the datasource. Also do not forget to close the connection after you used it (in a try/finally clause). With pooling, it works like a JDBC connection pool: when the pool/EJB container decides it does not need the instance anymore (e.g when it wants to reduce the number of instances or when a non application exception is thrown), then the @PreDestroy method wil be called.
Community
  • 1
  • 1
V G
  • 18,822
  • 6
  • 51
  • 89
  • Thanks Andrei for your reply, I understand what is stateful bean and I agree with you in the first point, But it doesn't answer my question about thread safety. So I will modify the example and use a simple instance variable... Note that its not a real life example, but its just an example I gave to clarify more my concerns – Tarik Aug 26 '15 at 16:23
  • For the second answer, connection is just an example too, what I need to understand is what happen under the hood? how @Predestroy work with pooling? – Tarik Aug 26 '15 at 16:39
  • @Tarik I have added new details about thread-safety. Basically your classes are thread safe if you let the EJB instance to be thread confined. Otherwise in most cases they are not thread-safe (becuase the `EntityManager` class is not thread-safe, which is use in most EJBs) – V G Aug 27 '15 at 13:19