我有一个用例,我希望将条目从多个线程填充到数据结构中,并在达到特定大小后开始删除旧记录。所以我决定使用Guava Loading Cache。
我想从多个线程中将条目填充到我的加载缓存中,并且我将基于驱逐的策略设置为Size Based Eviction
。
private final ScheduledExecutorService executorService = Executors
.newSingleThreadScheduledExecutor();
private final LoadingCache<String, DataBuilder> cache =
CacheBuilder.newBuilder().maximumSize(10000000)
.removalListener(RemovalListeners.asynchronous(new CustomListener(), executorService))
.build(new CacheLoader<String, DataBuilder>() {
@Override
public DataBuilder load(String key) throws Exception {
// what I should do here?
// return
}
});
// this will be called from multiple threads to populate the cache
public void addToCache(String key, DataBuilder dataBuilder) {
// what I should do here?
//cache.get(key).
}
我将从多个线程调用我的addToCache
方法来填充cache
。我很困惑我应该在addToCache
方法中做什么来填充缓存以及我的load
方法是什么样的?
此处DataBuilder
是我的构建器模式。
答案 0 :(得分:10)
显然你的问题是你没有得到CacheLoader
的主要目的。
CacheLoader
用于在调用get(K key)
或getUnchecked(K key)
时自动加载给定键的值(在缓存中不存在),即使我们有几个线程试图同时获取相同键的值,只有一个线程实际上会加载该值,一旦完成所有调用线程将具有相同的值。
当要加载的值需要一些时间时,这通常很有用,例如,当它是数据库访问或长计算的结果时,因为需要的时间越长,有多个线程尝试加载的可能性在没有确保只有一个线程将为所有调用线程加载数据的机制的情况下浪费资源的同一个值。
所以这里假设您的DataBuilder
实例很难构建,或者您只需要确保所有线程对于给定键都具有相同的实例,那么您确实需要{{1}它看起来像这样:
CacheLoader
感谢new CacheLoader<String, DataBuilder>() {
@Override
public DataBuilder load(String key) throws Exception {
return callSomeMethodToBuildItFromTheKey(key); // could be new DataBuilder(key)
}
}
,您无需再显式调用CacheLoader
,因为调用put
或cache.get(myKey)
的线程会在场景后面填充缓存。
如果您想手动填充缓存,只需使用put(K key, V value)
方法,就像下一个Cache
一样:
cache.getUnchecked(myKey)
如果您打算自己填充缓存,则不需要public void addToCache(String key, DataBuilder dataBuilder) {
cache.put(key, dataBuilder);
}
,只需拨打build()
而不是CacheLoader
即可构建您的build(CacheLoader<? super K1,V1> loader)
实例(它不再是Cache
。
您的代码将是:
LoadingCache