java - Spring @Cacheable 双重检查锁定(infinispan 后端)

标签 java spring caching infinispan

我最近开始在应用程序中使用 Spring 的 @Cacheable 注释来缓存一些昂贵操作的结果。我想要替换的代码广泛使用双重检查锁定模式来确保缓存的一致性以及昂贵例程的执行一次,如下所示:

final String key = SomeClass.computeKey(input)
String cachedValue = mCache.get(key);
if (cachedValue == null) {
    synchronized (mCache) {
        cachedValue = mCache.get(key);
        if (cachedValue == null) {
            cachedValue = expensiveComputing(input);  // must not be executed twice
            mCache.put(key, cachedValue);
        }
    }
}

上面的内容被替换为:

@Cacheable(value="someCache", key="T(SomeClass).computeKey(#input)")
public String expensiveComputing(Object input) {
    // must not be executed twice
} 

有时会有第二个缓存来缓存实际查找的锁对象,以避免在计算缓存值期间对整个缓存进行大量同步。

我已经读过infinispan's docu on locking我仍然想知道我是否需要自己处理这些方面,或者 infinispan 是否能保证预期的行为。

根据文档,自 5.0 以来,infinispan 默认为每个缓存条目创建一个新锁(我使用的是 8.2.6)。也就是说锁对象和缓存值的二级缓存应该是不必要的,如果我理解正确的话?!但是双重检查锁定模式又如何呢?这个也可以去掉吗?在高度并发的环境中,exppressiveComputing 例程是否仍然只被调用一次?

最佳答案

简短回答

Spring 4.3+ 和 Infinispan 9.0+ 支持此功能,并在 @Cacheable 中使用 sync=true(请参阅 this Spring ticketthis Infinispan ticket)

长答案

Spring 4.3之前,简单地用@Cacheable注释方法不会同步代码本身。它所做的只是将方法包装到代理中(有关详细信息,请参阅 o.s.c.a.JCacheCacheAspecto.s.c.j.i.JCacheAspectSupport),当它尝试从中获取值时,不包含任何额外的同步在调用方法体之前进行缓存。

因此,昂贵的计算完全有可能发生两次。在这种情况下,额外的同步取决于程序员。所以双重检查锁定还是有用的。

还有另一个选择:由于 Infinispan 将其缓存库作为 JCache (JSR-107) 提供程序提供,您可以考虑使用默认的 org.infinispan.jcache.annotation.InjectedCacheResultInterceptor,而不是使用默认的 org.infinispan.jcache.annotation.InjectedCacheResultInterceptor,编写您自己的 org.infinispan.jcache.annotation.AbstractCacheResultInterceptor 实现,它将负责锁定。例如,您的类的实现可能有一些字典来决定什么类型的 InitationContext 需要此类锁定。

实际上,在这种情况下使用@Cacheable看起来弊大于利。从事务管理器创建缓存并使用它对事务进行一些控制,就像在 Infinispan 中那样 tutorials似乎更容易、更简洁。

自 Spring 4.3 起,@Cacheable 具有 sync属性暗示整个操作必须同步。 Infinispan 从 9.0 版本开始支持此功能。

关于java - Spring @Cacheable 双重检查锁定(infinispan 后端),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44880927/

相关文章:

caching - 内存缓存 VS。分布式系统中的集中式缓存

java - joda时间到sql MS access数据库

java - 使用 Spring MVC 设置输入文本的日期格式

java - 仅更改 application.property spring 中的一个属性

java - 使用外部身份验证源时如何在 Spring Boot 中模拟身份验证

javascript - 在浏览器中使用 Javascript 预缓存文件?

javascript - 使用 <script> 标签提供 .cfm 文件

java - Tomcat JNDI : Data Source fails to initialize

java - 如果存在特定键 Java 8 的值,则检查列表映射

java - Spring @Autowired 令人困惑