我有一个用例,我希望从多个线程将条目填充到数据结构中,并在达到特定大小后开始删除旧记录.所以我决定使用Guava Loading Cache.
我想从多个线程将条目填充到我的加载缓存中,并且我将基于驱逐的策略设置为Size Based Eviction
.
private final ScheduledExecutorService executorService = Executors .newSingleThreadScheduledExecutor(); private final LoadingCachecache = CacheBuilder.newBuilder().maximumSize(10000000) .removalListener(RemovalListeners.asynchronous(new CustomListener(), executorService)) .build(new CacheLoader () { @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
是我的构建模式.
显然你的问题是你没有得到一个主要目的CacheLoader
.
A CacheLoader
用于在调用时自动加载给定键的值(在缓存中不存在),get(K key)
或者getUnchecked(K key)
即使我们有多个线程试图同时获取同一个键的值,一个线程实际上会加载该值,一旦完成所有调用线程将具有相同的值.
当要加载的值需要一些时间时,这通常很有用,例如,当它是数据库访问或长计算的结果时,因为需要的时间越长,有多个线程尝试加载相同值的可能性越大在没有确保只有一个线程将为所有调用线程加载数据的机制的情况下浪费资源的同时.
所以这里假设你DataBuilder
的实例很长,或者你只需要确保所有线程都有一个给定键的相同实例,那么你确实需要一个CacheLoader
,它看起来像这样:
new CacheLoader() { @Override public DataBuilder load(String key) throws Exception { return callSomeMethodToBuildItFromTheKey(key); // could be new DataBuilder(key) } }
多亏了CacheLoader
,你有没有必要要求put
再明确地为您的缓存会幕后由线程调用来填充cache.get(myKey)
或cache.getUnchecked(myKey)
.
如果要手动填充缓存,只需使用下一个put(K key, V value)
方法即可Cache
:
public void addToCache(String key, DataBuilder dataBuilder) { cache.put(key, dataBuilder); }
如果你打算自己填充缓存,你不需要CacheLoader
,你可以简单地调用build()
而不是build(CacheLoader super K1,V1> loader)
构建你的Cache
实例(它不再是一个LoadingCache
).
您的代码将是:
private final Cachecache = CacheBuilder.newBuilder().maximumSize(10000000) .removalListener( RemovalListeners.asynchronous(new CustomListener(), executorService) ).build();