【发布时间】:2015-11-20 17:19:28
【问题描述】:
我不明白 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.池化 vs 线程安全:
用户 1 使用了 BeanTest 的实例,并使用 modify 方法修改了 var,然后他完成并且容器将 BeanTest 的实例放入托管池中。当用户 2 尝试对请求使用相同的 bean 时,他可能得到相同的 BeanTest 实例,最初由用户 1 修改(我知道这也可能得到另一个实例)。那么他会找到实例变量var 的哪个状态(默认值null 或"TestName")?如果它是新修改的,这是否意味着即使@Stateless bean 也不是 100% 线程安全的?所以最后没有关于线程安全的容器附加值,因为不使用实例变量使 bean 线程安全,即使它不是 @Stateless bean
2。池化 vs @PreDestroy
如果 bean 返回到托管池并且没有被销毁,这是否意味着不会调用 @Predestroy 方法并且在这种情况下连接将保持打开状态?因此,如果池中有 30 个该 bean,我们可能有 30 个未使用的打开连接,这不是性能问题吗?或者这不是@Predestroy 与池结合的方式? (使用Connection 只是一个例子,我们可能有其他类型的资源需要在@Predestroy 中关闭)
注意: 这不是一个真实的例子,所以我不是在寻找替代解决方案,我关心的是理解整个概念以及如何在应用程序中管理事物服务器,幕后发生了什么
【问题讨论】:
-
您的担心正是我尽可能避开 EJB 的原因。使用 Spring,您不会得到这种无意义、定义不明确的语义。
-
也许您应该使用
@Stateful而不是@Stateless? -
另外,您应该在需要时获得连接,而不是在初始化 ejb 时。
-
@BheshGurung 感谢您的回复,但我想了解为什么它不是线程安全的,我不是在寻找替代方案,因为它不是现实生活中的问题
-
实际上是线程安全的。为什么说它不是线程安全的?如果某个其他线程已经获得了实例,则该线程不可能获得它。
标签: java multithreading jakarta-ee ejb ejb-3.1