1

我已经在我的 java EE 应用程序中实现了一个断路器模式,并且因为它拥有一个状态(有多少失败的请求、平均响应时间、锁定/解锁等等),所以我将 inte 设置为@Stateful. 并且为了避免由于容器锁定而导致序列化出现问题,我添加了@ConcurrencyManagement(ConcurrencyManagementType.BEAN)并确保所有操作都是线程安全的。

所以它目前看起来像这样:

@Stateful
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class CatalogBreaker extends Breaker {

但我仍然得到。

Caused by: javax.ejb.ConcurrentAccessTimeoutException: WFLYEJB0228: EJB 3.1 FR 4.3.14.1 concurrent access timeout on CatalogBreaker - could not obtain lock within 5000 MILLISECONDS

但是,如果我正确理解了所有内容,则CuncurrencyManagement注释应该将锁定委托给 bean 而不是容器......并且由于CatalogBreaker没有任何锁或任何类似的东西,那么我怎么会得到这个错误?

4

1 回答 1

0

据我所知,有状态的 EJB 总是被写锁锁定,但是我很难找到任何官方的 Oracle 文档来说明这一点(因此语言:“据我所知”)。

换句话说,注释@ConcurrencyManagement(ConcurrencyManagementType.BEAN)什么也不做。对有状态 EJB 的业务方法的同一实例的每次调用都会阻塞下一个,因此有状态 EJB 的任何两个业务方法都不能同时执行。

如果您有多个线程尝试同时访问有状态 EJB,容器将阻止它们这样做,这解释了您的性能损失。

超时默认为 5 秒,在您的日志中也显示为默认值。您可以使用AccessTimeout调整值,但我相信大多数人会认为这样做是不好的做法。我想大多数人都会同意,如果你达到了那个超时时间,那么你需要重新考虑你的设计。默认值为 5 秒的原因是因为容器希望所有工作都是短暂的任务。您正在超时,不是因为您的工作花费了太长时间,而是因为您使用有状态 EJB 的方式不符合容器期望您使用它的方式。并不是说你这样做的方式是错误的,只是不正确......有点像容器用它爸爸的声音说:我没有生气,只是失望。

于 2018-10-15T15:34:53.700 回答