我遇到了 Guava Caches 的问题。当我在缓存中只有一个元素时,一切都很好。但是当我加载第二个元素时,它试图用较早输入的键进行选择
private static LoadingCache<String, MyClass> cache = null;
....
public MyClass method(final String id1, final long id2) {
log.error("inside with "+id1);
final String cacheKey = id1+"-"+id2;
if(cache == null){
cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.build(
new CacheLoader<String, MyClass>() {
@Override
public MyClass load(String key) {
return getValue(cacheKey);
}
}
);
}
try {
return cache.get(cacheKey);
} catch (ExecutionException ex) {
log.error("EEE missing entry",ex);
}
}
private MyClass getValue(String cacheKey){
log.error("not from cache "+cacheKey);
...
}
日志说:
inside with 129890038707408035563943963861595603358
not from cache 1663659699-315839912047403113610285801857400882820 // This is key for the earlier entry
例如,当我调用 method("1", 2) 时,它会将值加载到缓存中,随后我可以从缓存中获取它。现在我调用方法 ("3", 4),这不在缓存中,因此调用 getValue() 并且日志打印出方法 ("1", 2) 的键
我哪里错了?
最佳答案
您的问题与您如何创建 CacheLoader
有关,如果你检查得很好,你会看到你用给定的缓存键(缓存延迟初始化时局部变量 cacheKey
的值)初始化它,而它应该更通用并依赖于 key
作为参数提供给方法 load
你的CacheLoader
否则它将通过调用 getValue(key)
加载缓存使用相同的 key 。
应该是这样的:
new CacheLoader<String, MyClass>() {
@Override
public MyClass load(String key) {
return getValue(key); // instead of return getValue(cacheKey);
}
}
注意:您初始化缓存的方式不是线程安全的,事实上如果它还没有被初始化并且您的方法method
被多个线程同时调用,它将被创建多次而不是一次。
一种方法可能是使用双重检查锁定习惯用法,如下所示:
private static volatile LoadingCache<String, MyClass> cache = null;
public MyClass method(final String id1, final long id2) {
...
if(cache == null){
synchronized (MyClass.class) {
if(cache == null){
cache = ...
}
}
}
注意:不要使用 CacheLoader
初始化静态缓存基于非静态 方法,它太容易出错了。将它们设为非静态或静态,但不要混合使用。
假设您可以将两者设为静态,您的缓存初始化将非常简单,它只是:
private static final LoadingCache<String, MyClass> cache = CacheBuilder.newBuilder()...
不需要懒惰地初始化它,这也会大大简化你的方法的代码,因为它会简单地减少到:
public MyClass method(final String id1, final long id2) {
log.error("inside with "+id1);
final String cacheKey = id1+"-"+id2;
try {
return cache.get(cacheKey);
} catch (ExecutionException ex) {
log.error("EEE missing entry",ex);
}
}
关于java - 考虑到旧 key 的 Guava 缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39304919/