缓存是否需要同步?

时间:2009-01-30 20:14:48

标签: c# java multithreading caching

这似乎是一个天真的问题,但我与同事进行了讨论,我认为没有真正需要缓存是线程安全/同步的,因为我认为它无关紧要谁输入一个值,因为给定键的值应该是“常量”(因为它最终来自同一个源)。如果值可以随时更改,那么缓存本身似乎并不是全部有用(如果您关心该值是“当前正确”,则应该转到原始源)。

我认为至少使GET同步的主要原因是,如果在缓存中遗漏并且您不希望多个线程各自出去获取值以放回缓存中,则非常昂贵。即使这样,你也需要在read-fetch-put循环期间阻止所有消费者的东西。

无论如何,我的工作假设是哈希本质上是线程安全的,因为对于任何{k​​ey,value}组合,该值为null或者无关紧要“谁”首先去那里写。

问题是:这是一个合理的假设吗?

更新:我的问题的真正范围是非常简单的id->值样式缓存(或{parameters} - > {计算值},其中无论谁写入缓存,值都是相同的,我们只是试图从“重新计算”/回到数据库中保存。对象的实际图形是不相关的,缓存通常是长寿的。

5 个答案:

答案 0 :(得分:4)

对于哈希的大多数实现,您需要进行同步。如果需要扩展/重新散列哈希表怎么办?如果两个线程试图将某些东西添加到哈希表中,其中键是不同的,但是哈希碰撞了怎么办?它们可以同时以不同的方式修改哈希表中的相同槽。假设您正在使用哈希表来实现缓存(您在问题中暗示了这一点),如果您还不熟悉,我建议您仔细阅读hash tables are implemented的详细信息。

答案 1 :(得分:2)

写入并不总是原子的。您必须使用原子数据类型或提供一些同步(RCU,锁等)。没有共享数据本身就是线程安全的。或者通过坚持无锁算法(即在可能和可行的情况下)使其消失。

答案 2 :(得分:1)

只要获取和释放锁的成本低于重新创建对象的成本(从文件或数据库或其他任何方式),所有对高速缓存的访问确实应该同步。如果不是你根本不需要缓存。 :)

答案 3 :(得分:1)

如果要避免数据损坏,则必须进行同步。当缓存包含必须以原子方式更新的多个表时尤其如此。想象一下,你有一个DMV数据库(汽车部门)。您向数据库添加一个新人,该人将拥有自动注册记录以及收到的家庭住址记录和其他联系信息的记录。如果您不以原子方式更新这些表 - 在缓存中的数据库 - 那么任何从缓存中提取数据的客户端都可能会获得不一致的数据。

是的,任何一个数据都可以是常量,但数据库通常包含的数据 - 如果不一起更新和原子地 - 可能导致数据库客户端获得不正确或不完整或不一致的结果。

答案 4 :(得分:0)

如果您使用的是Java 5或更高版本,则可以使用ConcurrentHashMap。这以线程安全的方式支持多个读者和编写者。

相关问题