EJB Pooling与线程安全和@PreDestroy

时间:2015-08-26 15:17:59

标签: java multithreading java-ee ejb ejb-3.1

我无法理解EJB容器如何使用实例变量管理@Stateless bean的线程安全性。在解释我的担忧之前,我将举一个简单的例子:

@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();
    }
}
}

这是我的问题,假设我们的容器支持池:

1。 Pooling vs Thread-safe:

用户1使用BeanTest的实例并使用modify方法修改了var,然后他完成了,容器将BeanTest的实例放入托管池中。当用户2尝试将同一个bean用于请求时,他可能获得由用户1初步修改的BeanTest的相同实例(我知道也可能获得另一个实例)。那么他会找到实例变量var的哪个状态(默认值为null"TestName")?如果它是新修改的那个,这是否意味着即使@Stateless bean不是100%线程安全的?所以finnaly没有关于线程安全性的容器添加值,因为不使用实例变量使得bean线程安全,即使它不是@Stateless bean

2。合并vs @PreDestroy

如果bean被返回到托管池而没有被销毁,那么这是否意味着不会调用@Predestroy方法,在这种情况下连接将保持打开状态?那么,如果我们在池中有30个inft,我们可能有30个未使用的开放连接,这不是性能问题吗?或者这不是@Predestroy如何与汇集相结合? (使用Connection只是一个示例,我们可能需要在@Predestroy中关闭其他类型的资源)

NB: 这不是一个真实的例子,所以我不是在寻找替代解决方案,我关心的是理解整个概念以及如何在应用程序中管理事物服务器,幕后发生的事情

2 个答案:

答案 0 :(得分:2)

1)容器保证线程安全,这意味着单个线程一次可以访问给定的SLSB。它与保证状态不会改变无关。 BTW在SLSB中具有可变状态毫无意义。

2)您不希望在SLSB的生命周期内保持连接,因为您有效地阻止它返回到池中而冒疲惫。

答案 1 :(得分:1)

  1. 如果注入的AnotherBean是无状态的,那么调用AnotherBean.setName()是没有意义的。如果它是有状态的,那么将一个有状态的bean注入一个无状态的bean是没有意义的(检查是为什么有状态的bean)。关于线程安全:容器不能使你的类线程安全,但它保证单个客户端线程一次使用某个EJB实例(检查Chris的回答引用)。因此,如果您不在EJB客户端的不同线程中使用EJB,那么使用thread confinment 代码是线程安全的
  2. 不要在无状态bean中使用实例变量,然后再使用实例变量。否则,您与@Stateful注释不一致。因此,删除connection状态变量。无论如何,你不想只为你的bean保持一个开放的连接:每次从数据源获取它。另外,在使用它之后不要忘记关闭连接(在try / finally子句中)。使用池时,它的工作方式类似于JDBC连接池:当池/ EJB容器决定它不再需要实例时(例如,当它想要减少实例数或者抛出非application exception时),那么将调用@PreDestroy方法。