【发布时间】:2015-12-22 13:58:40
【问题描述】:
在我的应用程序中,我在@Singleton EJB 中提供了一些应用程序范围的数据。数据的准备是一项长期运行的任务。然而,这个结果的根本来源是经常变化的,所以我也必须经常重新计算由 Singleton 填充的数据。
现在的任务是确保快速访问数据,即使当前正在重新计算。在准备中,我是否暴露旧状态无关紧要。
我目前的做法是这样的:
@Singleton
@Startup
@Lock(LockType.READ)
public class MySingleton {
@Inject private SomeService service;
@Getter private SomeData currentVersion;
@PostConstruct
private void init() {
update();
}
private void update() {
currentVersion = service.longRunningTask();
}
@Lock(LockType.WRITE)
@AccessTimeout(value = 1, unit = TimeUnit.MINUTES)
@Asynchronous
public void catchEvent(
@Observes(during = TransactionPhase.AFTER_SUCCESS) MyEvent event) {
this.update();
}
}
这背后的想法是在启动时准备一次数据。之后,客户端可以同时访问我的数据的当前版本(将此数据视为不可变的)。
现在,如果发生某些可能导致重新计算数据的操作,我将触发 CDI 事件,并且在单例中,我正在观察此事件并再次触发重新计算。这些动作可能在短时间内经常发生(但也可能很长一段时间内都没有这些动作)。
- 我将该方法标记为@Asynchronous,因此它被执行,因此其他客户端仍然可以在不同的执行线程中同时访问getter。
- 我将其标记为 LockType.Write 并使用 AccessTimeout,因为我想在它们在短时间内发生时删除冗余事件。
问题很明显:
- 如果我使用的是
LockType.WRITE,那么在重新计算期间,对 getter 方法的访问也会被锁定。 - 如果我不使用它,当观察到许多 CDI 事件时,我最终会消耗大量资源
是否可以只锁定对这个单一方法的访问,而不是锁定对我的单例的整个实例的访问?这会解决我的问题吗?还有其他方法可以解决我的问题吗?
如何处理?
【问题讨论】:
标签: jakarta-ee ejb ejb-3.1