【发布时间】:2012-01-06 20:56:40
【问题描述】:
我有一个 Guava Cache(或者更确切地说,我正在从 MapMaker 迁移到 Cache),这些值代表长期运行的工作。我想将expireAfterAccess 行为添加到缓存中,因为这是清理它的最佳方式;但是,即使在一段时间内没有通过缓存访问该作业,它也可能仍在运行,在这种情况下,我需要防止它从缓存中删除。我有三个问题:
重新插入在
RemovalListener回调期间被删除的缓存条目是否安全?-
如果是,它是否是线程安全的,这样
李>CacheLoader不可能为该键生成第二个值,而RemovalListener回调仍在另一个线程中发生? 有没有更好的方法来实现我想要的?这不仅仅是/只是一个“缓存” - 每个键使用一个且只有一个值是至关重要的 - 但我也想在它所代表的作业完成后将条目缓存一段时间。我之前使用过
MapMaker,现在我需要的行为在该类中已弃用。在作业运行时定期 ping 地图是不优雅的,在我的情况下,是不可行的。也许正确的解决方案是拥有两张地图,一张没有驱逐,一张有,并在完成时迁移它们。
我也会提出功能请求 - 这将解决问题:允许锁定单个条目以防止驱逐(然后解锁)。
[编辑以添加一些细节]:此映射中的键是指数据文件。这些值可以是正在运行的写入作业、已完成的写入作业,或者 - 如果没有正在运行的作业 - 一个只读的、查找时生成的对象,其中包含从文件中读取的信息。重要的是每个文件恰好有零个或一个条目。我可以为这两件事使用单独的地图,但必须在每个密钥的基础上进行协调,以确保一次只存在一个或另一个。就获得正确的并发性而言,使用单个映射使其更简单。
【问题讨论】:
-
我不得不承认我倾向于使用两张地图的解决方案,但我会使用一张地图和一张缓存。将地图用于仍在进行中的作业,或者使用缓存的 RemovalListener 从地图中删除条目?
-
有趣的想法@Louis。我一直对两个地图解决方案持怀疑态度,因为我不想在两个不同的地图中查找内容,并处理围绕它的并发问题。如果我的
Cache只包含已完成的工作,我可以改用expireAfterWrite,这样我可以将它们保留一段时间,RemovalListener会将它们从主地图中删除。没有什么会使用Cache。尽管采用这种方法,但使用Cache确实没有任何意义。我真正需要的只是使用ScheduledThreadExecutor安排删除时间。 -
转念一想,我不能那样做,因为这个缓存实际上是一个缓存 - 大多数条目没有执行作业,而只是需要在一段时间后过期的只读引用时期。我真正需要的是锁定其中一些的能力——我最初关于通过
RemovalListener重新插入的问题只是实现锁定的一种方式。 -
我真的不清楚在什么情况下你会锁定某些东西,在什么情况下你不应该。
-
如果映射表示本地服务器上正在运行的作业,它可能存在于另一个线程中,那么弱引用会提供您需要的自动清理吗?没有足够的信息来建议最佳策略,恕我直言。
标签: java caching concurrency guava