正如 BalusC 完全问的那样,最大的问题是您希望在什么粒度级别上执行此锁定?每个登录用户,所有用户,或者您可以通过每个请求锁定?
或者,这将是一个更难的问题,是单页请求获取锁然后该特定页面旨在保持请求之间的锁的想法吗?例如,作为一种预订。我正在浏览一个酒店页面,当我只是查看一个房间时,我已经在系统中为该房间进行了隐式预订,所以在我查看时不会发生其他人真实预订房间的情况?
在后一种情况下,也许以下方案会起作用:
- 在应用范围内,定义一个全局并发映射。
- 地图的键代表您要保护的资源。
- 映射的值是一个自定义结构,它持有一个读写锁(例如 ReentrantReadWriteLock)、一个令牌和一个时间戳。
- 在应用范围内,还有一个全局锁(如 ReentrantLock)
- 请求中的代码首先获取全局锁,然后快速检查映射中的条目是否存在。
- 如果该条目在那里,则它被采用,否则它被创建。创建时间应该很短。全局锁很快被释放。
- 如果条目是新的,它会通过它的写锁被锁定,并创建一个新的令牌和时间戳。
- 如果条目不是新条目,则通过其读锁锁定
- 如果代码具有相同的令牌,它可以继续访问受保护的资源,否则它检查时间戳。
- 如果时间戳已过期,它会尝试获取写锁。
- 写锁超时。当超时发生时,放弃并向客户传达一些信息。否则会创建一个新的令牌和时间戳。
这只是一般的想法。在我构建的 Java EE 应用程序中,我使用了类似的东西(尽管不完全相同)并且效果很好。
或者,您无论如何都可以使用定期删除过时条目的石英作业。另一个替代方案是用例如 JBoss Cache 或 Infinispan 实例替换全局并发映射。这些允许您为其条目定义驱逐策略,这使您不必自己编写代码。但是,如果您从未使用过这些缓存,那么学习如何正确设置和配置它们可能比自己构建一个简单的石英作业更麻烦。