是啥锁定了我的有状态 bean

Posted

技术标签:

【中文标题】是啥锁定了我的有状态 bean【英文标题】:What is locking my stateful bean是什么锁定了我的有状态 bean 【发布时间】:2018-07-12 17:18:56 【问题描述】:

我已经在我的 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 没有任何锁或任何类似的东西,那么我怎么会得到这个错误?

【问题讨论】:

查看 Javadoc 中的 ConcurrencyManagement 注释。看起来如果它应用于有状态 bean,您就不能使用 ConcurrencyManagementType.BEAN。 是的,我刚刚注意到了。但是,即使调用的函数非常基本并且应该很快,我仍然会遇到巨大的性能损失(这可能与此问题无关) 【参考方案1】:

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

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

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

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

【讨论】:

以上是关于是啥锁定了我的有状态 bean的主要内容,如果未能解决你的问题,请参考以下文章

JSF 请求范围的 bean 不断在每个请求上重新创建新的有状态会话 bean?

Flutter 中的有状态和无状态小部件之间的关系是啥?

使用 Google Cloud Platform 时 Terraform 状态锁定的机制是啥?

雷林鹏分享:EJB有状态会话Bean

雷林鹏分享:EJB有状态会话Bean

Web 应用程序中的有状态 EJB?