【问题标题】:Concurrent Cache modification in JavaJava中的并发缓存修改
【发布时间】:2013-10-17 17:54:58
【问题描述】:

我正在构建一个带有 Map 的小型缓存,其中包含一些数据库查询的缓存结果。假设这个缓存是以线程安全的方式填充的。我的问题是关于此缓存中的条目,即 Result 类型的对象。

考虑以下场景:

线程 1 从缓存中读取并获取一些 Result 对象,称之为 R。 线程 2 想要同一个对象 R 被杀死,所以它调用缓存来杀死对象 R。

看到两个线程如何只持有对对象 R 的引用,有可能对象 R 突然为线程 1 变为空,因为线程 2 已调用杀死它。

如何避免这种情况?当线程从缓存中读取时,我是否应该制作对象 R 的深层副本,以便即使线程 2 杀死缓存,线程 1 仍然能够完成它正在做的事情而不会出现问题?或者有另一种方法吗?我在线程和并发方面的经验并不是最丰富的,所以要温柔......

【问题讨论】:

  • 您需要显示整个 Result 类型,因为它对这个问题很重要;一般来说,不可变或正确同步的 Result 就可以了。请记住,object 不能为 null,只能为对象的 reference。如果线程 1 在线程 2 从缓存中逐出 R 之前获取了有效引用,则引用本身仍然有效。
  • 这取决于你的杀死机制!如果你只是从他们的 Map 中删除它,那么线程 1 的逻辑不会发生任何事情,因为它持有它的引用,但是如果你修改它(例如通过使其成员无效),那么线程 1 就会遇到问题。
  • 您只缓存对对象的引用,因此只要在删除时不更改对象本身就没有问题(如@AmirPashazadeh 所述)。另一件事:如果可能的话,我建议您使用缓存库,例如 EHCacheGuava Cache
  • @ortang 你当然是对的,我只缓存引用。早该想到的……

标签: java caching concurrency thread-safety


【解决方案1】:

是的——通常您将 Result 视为一个值对象。线程 2 会将其从缓存中删除/ 或用更新的值覆盖缓存,但通常不会损坏/破坏 R 的 内部状态

线程 2“将 null 放入缓存”或“将新值放入缓存”本身不会影响使用 R 的任何其他引用或线程。R 中的任何内容都不会破​​坏,除非您专门破坏它。从缓存中请求对象的代码将不再获得对 R 的特定引用。

指针/或引用将更改或设置为 null,R 本身的状态和字段不会。

这假设 R 不持有需要释放的资源..

如果 R 确实 需要保存资源,这不是通常的情况,那么您可能需要添加一个 in-use 计数器 并计算两者都在使用中通过被保存在缓存中并被客户端代码使用,这样 R 的资源只有在计数器减为零时才被释放。

但这将是一个不寻常的要求。

【讨论】:

    【解决方案2】:

    如果您的“kill”操作修改了 Result 的内部结构,那么您可能会遇到这个问题。 如果不是,则已从缓存中接收到它的线程的引用不能变为空。从地图中删除对象不会使引用为空。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-07
      • 1970-01-01
      • 2011-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多