java - EJB 池与线程安全和@PreDestroy

标签 java multithreading jakarta-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。池化与线程安全:

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

<强>2。池化 vs @PreDestroy

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

注意: 这不是现实生活中的例子,所以我不是在寻找替代解决方案,我关心的是理解整个概念以及如何在应用程序中管理事物服务器,引擎盖下发生了什么

最佳答案

我认为你说的Thread-Safety就是不可重入子句

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

您可以在无状态 session bean 中忽略 EJB 编程限制,创建一组线程并执行非线程安全的操作。容器不会阻止你。由于线程管理冲突,这可能会导致各种错误。

容器只 promise 一次只允许 1 个线程访问无状态 ejb。 (关于单例有一些不同的规则)

你是对的,如果实例返回到你的示例中的连接可以建立的池中。因为 been 实例当然仍然存在。

如果您深入研究应用服务器文档,即 Glassfish EJB 池调整章节,您会发现默认设置是销毁对象实例而不是将它们返回到池中。与 JDBC 连接相同,它将被关闭和清理。重用是一种选择,在这种情况下,如果您尝试在 SSB 中创建状态,则可能会消耗一些额外的内存。如果实例在池中闲置,我认为不会对性能产生太大影响。

确切的池化实现取决于应用服务器供应商,只要他们遵守规范即可。我想你会发现默认行为是在使用后销毁实例。这会导致托管资源得到清理。

但是所有这些都有些无声,在您的示例中,您正试图在类中存储一个状态,即连接字段。无需在无状态组件中创建状态,这不是此类组件的用途。 Java EE 体系结构的其他部分处理状态。 (实体、有状态的 beans、JCA)

关于java - EJB 池与线程安全和@PreDestroy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32230502/

相关文章:

c++ - 在创建线程时无法理解此错误

python - 使用 Tkinter 进行线程化

java - Spring Cloud Gateway 和容错

java - 如果输入的不是数字则显示错误消息

Java 小程序 : Cant figure out how to display rectangle on keypressed

java静态同步方法

hibernate - ORA-01400 : Cannot insert null into (TABLE. 列)( hibernate )

jakarta-ee - maven 耳朵/ war 问题和 "deploy on save"不工作

java - JaxbRepresentation 给出错误 "doesnt contain ObjectFactory.class or jaxb.index"

java - 使用匹配器的mockito的InvalidUseOfMatchersException