gpt4 book ai didi

具有单个更新程序线程的 Java 多线程缓存

转载 作者:搜寻专家 更新时间:2023-11-01 03:44:56 31 4
gpt4 key购买 nike

我有一个平均同时运行约 1k 个请求线程的 Web 服务。这些线程从缓存(当前在 ehcache 上)访问数据。当缓存中的条目过期时,命中过期条目的线程尝试从 DB 获取新值,而其他线程也尝试命中该条目 block ,即我使用 BlockingEhCache 装饰器。我不想让其他线程等待“获取线程”,而是希望其他线程使用与“丢失”键相对应的“陈旧”值。是否有第 3 方为此目的开发了 ehcache 装饰器?你知道有这种行为的任何其他缓存解决方案吗?其他建议?

最佳答案

我对 EHCache 的了解不够好,无法给出具体的建议来解决您的问题,所以我将概述在没有 EHCache 的情况下我会做什么。

让我们假设所有线程都使用名为 FooService 的服务接口(interface)和名为 SimpleFooService 的服务 bean 访问此缓存。该服务将具有获取所需数据(也被缓存)所需的方法。这样你就隐藏了它是从前端缓存的事实(http 请求对象)。

我们不是简单地将要缓存的数据存储在服务的属性中,而是为它创建一个特殊的对象。我们称它为 FooCacheManager。它将缓存存储在 FooCacheManger 的一个属性中(假设它是 Map 类型)。它将有获取缓存的 setter/getter 。它还会有一个特殊的方法叫做 reload(),它会从 DB 中加载数据(通过调用一个服务方法来获取数据,或者通过 DAO),并替换缓存中的内容(保存在一个属性中) .

这里的技巧如下:

  1. 在 FooCacheManger 中声明缓存属性为 AtomicReference (Java 1.5 中声明的新对象)。这保证了读取和分配给它时的线程安全。您的读/写操作永远不会发生冲突,也不会读取一半的值。
  2. reload() 将首先将数据加载到一个临时 map 中,然后在完成后将新 map 分配给保存在 FooCacheManager 中的属性。由于属性是AtomicReference,赋值是原子的,所以基本上是瞬间刷图,不需要加锁。
  3. TTL 实现 - 让 FooCacheManager 实现 QuartzJob 接口(interface),并使其成为一个有效的 quartz 作业。在作业的执行方法中,让它运行 reload()。在 Spring XML 中将此作业定义为每 xx 分钟(您的 TTL)运行一次,如果您使用 PropertyPlaceHolderConfigurer,也可以在属性文件中定义它。

此方法有效,因为读取线程:

  1. 不要阻塞阅读
  2. 不要在每次读取时都调用 isExpired(),即 1k/秒。

写入线程在写入数据时也不会阻塞。

如果不清楚,我可以添加示例代码。

关于具有单个更新程序线程的 Java 多线程缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3826710/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com