何时要小心EJB中的多线程?

时间:2011-11-30 11:55:06

标签: multithreading java-ee thread-safety ejb-3.0

我理解App Server会处理线程,因此开发人员应该只专注于业务逻辑...... 但请考虑一个例子。无状态EJB具有CountManager类型的成员。

@WebService
@Stateless
public class StatelessEJB {
  private CountManager countManager;
  ... 
  public void incrementCount() {countManager.incrementCount();}
  public int getCount(){return countManager.getCount();}
}

和CountManager

 public class CountManager {
    public void increaseCount() {
    // read count from database
    // increase count 
    // save the new count in database table. 
    }

    public int getCount() {
    // returns the count value from database.
    }
}

开发人员应该考虑多线程。如果你使CountManager也是一个EJB,我想问题不会消失。 开发人员需要注意的一般准则是什么?

更新: 更改了代码。假设EJB的方法公开为webservice,因此我们无法控制客户端调用它们的顺序。 Transaction属性是默认值。在多线程场景下,此代码是否正常运行?

2 个答案:

答案 0 :(得分:2)

请注意,这不是同步或多线程的问题,而是事务行为的问题。

如果在EJB中运行,上述代码将通过将事务支持委派给数据库来处理竞争条件。根据隔离级别和事务属性,数据库可以负责锁定基础表,以确保信息保持一致,即使面对并发访问和/或修改也是如此。

答案 1 :(得分:2)

EJB是线程安全的这一事实并不意味着不同的方法调用将为您提供一致的结果。

EJB确保您的特定 EJB实例中的每个方法都将由一个线程执行。这并不能帮助您避免多个用户访问EJB的不同实例以及不一致的结果危险。

你的CountManager似乎是一个普通的Java类,这意味着你在无状态EJB中持有一个状态。这不好,在这种情况下,EJB线程安全不会保护您免受任何攻击。您的对象可以同时通过多个EJB实例进行访问。

在客户端的第一个方法调用StatelessEJB.incrementCount()(启动事务 - 默认TransactionAttribute)和第二个客户端的方法调用StatelessEJB.getCount()(启动事务)之间)许多事情可能会发生,count的价值可能会改变。

如果您将其更改为EJB,我认为您不会更安全。如果它是SLSB,它仍然不能有任何状态。如果状态没有被实现为EJB字段变量而是数据库获取数据,那么它肯定更好但仍然 - 事务对您来说不是真正的帮助,因为您的WebService客户端仍然分别执行这两个方法,因此登陆两个不同的事务。

简单的解决方案是:

  • 使用可与EJB事务同步的数据库(SLSB中没有状态)
  • 在事务中执行这两种方法(如WebService客户端的incrementAndGet(-)方法)。

你可以相当肯定你得到的结果是一致的。