是啥锁定了我的有状态 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?