weakValues() 和 expireAfterAccess() 可以结合使用吗?
Can weakValues() and expireAfterAccess() be combined?
我想做这样的事情:
CacheBuilder
.newBuilder()
.maximumSize(CONFIG.cacheMaxSize())
.expireAfterAccess(CONFIG.cacheTimeout(),
CONFIG.cacheTimeUnit())
.weakValues()
.build(cacheLoader);
我期望的行为是,只有在未引用该值且过期时间已过时,条目才会过期。这就是这种用法的工作方式吗?
否,如果未引用值或过期时间已过,条目将过期:
public class CacheBuilderIT {
@Test
public void expireAfterAccessWithWeakValues() throws InterruptedException {
Cache<Object, Object> cache = CacheBuilder.newBuilder()
.expireAfterAccess(500, MILLISECONDS)
.weakValues()
.build();
Object key = new Object();
Object value = new Object(); // keep a strong reference to the value
cache.put(key, value);
Thread.sleep(300);
assert cache.getIfPresent(key) != null : "expiration occurred too quickly";
Thread.sleep(300);
assert cache.getIfPresent(key) != null : "last access did not reset expiration";
Thread.sleep(1000);
assert cache.getIfPresent(key) != null : "reference did not prevent expiration";
}
}
输出:
java.lang.AssertionError: reference did not prevent expiration
不直接,因为只要不再有对该对象的强引用,弱值就可以被垃圾回收。然而,您可以做的是使用由两个独立缓存支持的 ForwardingCache
,一个弱值缓存和一个定时过期缓存,以便基于时间的缓存持有对对象的强引用,从而将其保存在弱值缓存。它看起来像这样:
public class WeakValuedExpiringCache<K, V> extends ForwardingCache<K, V> {
private final Cache<K, V> expiringCache;
private final Cache<K, V> weakCache;
public WeakValuedExpiringCache(CacheBuilder expiringSpec) {
expiringCache = expiringSpec.build();
weakCache = CacheBuilder.newBuilder().weakValues().build();
}
// weakCache is the canonical cache since it will hold values longer than
// expiration if there remain other strong references
protected Cache<K, V> delagate() {
return weakCache;
}
@override
public V get(K key, Callable<? extends V> valueLoader)
throws ExecutionException {
// repopulate the expiring cache if needed, and update the weak cache
V value = expiringCache.get(key, valueLoader);
weakCache.put(key, value); // don't call super.put() here
}
@Override
public void put(K key, V value) {
expiringCache.put(key, value);
super.put(key, value);
}
// Handle putAll(), cleanUp(), invalidate(), and invalidateAll() similarly
}
你也可以用 ForwardingLoadingCache
做同样的事情,就像上面的 .get()
你应该从 expiringCache
和 .put()
加载值到weakCache
在相关加载方法中。
我想做这样的事情:
CacheBuilder
.newBuilder()
.maximumSize(CONFIG.cacheMaxSize())
.expireAfterAccess(CONFIG.cacheTimeout(),
CONFIG.cacheTimeUnit())
.weakValues()
.build(cacheLoader);
我期望的行为是,只有在未引用该值且过期时间已过时,条目才会过期。这就是这种用法的工作方式吗?
否,如果未引用值或过期时间已过,条目将过期:
public class CacheBuilderIT {
@Test
public void expireAfterAccessWithWeakValues() throws InterruptedException {
Cache<Object, Object> cache = CacheBuilder.newBuilder()
.expireAfterAccess(500, MILLISECONDS)
.weakValues()
.build();
Object key = new Object();
Object value = new Object(); // keep a strong reference to the value
cache.put(key, value);
Thread.sleep(300);
assert cache.getIfPresent(key) != null : "expiration occurred too quickly";
Thread.sleep(300);
assert cache.getIfPresent(key) != null : "last access did not reset expiration";
Thread.sleep(1000);
assert cache.getIfPresent(key) != null : "reference did not prevent expiration";
}
}
输出:
java.lang.AssertionError: reference did not prevent expiration
不直接,因为只要不再有对该对象的强引用,弱值就可以被垃圾回收。然而,您可以做的是使用由两个独立缓存支持的 ForwardingCache
,一个弱值缓存和一个定时过期缓存,以便基于时间的缓存持有对对象的强引用,从而将其保存在弱值缓存。它看起来像这样:
public class WeakValuedExpiringCache<K, V> extends ForwardingCache<K, V> {
private final Cache<K, V> expiringCache;
private final Cache<K, V> weakCache;
public WeakValuedExpiringCache(CacheBuilder expiringSpec) {
expiringCache = expiringSpec.build();
weakCache = CacheBuilder.newBuilder().weakValues().build();
}
// weakCache is the canonical cache since it will hold values longer than
// expiration if there remain other strong references
protected Cache<K, V> delagate() {
return weakCache;
}
@override
public V get(K key, Callable<? extends V> valueLoader)
throws ExecutionException {
// repopulate the expiring cache if needed, and update the weak cache
V value = expiringCache.get(key, valueLoader);
weakCache.put(key, value); // don't call super.put() here
}
@Override
public void put(K key, V value) {
expiringCache.put(key, value);
super.put(key, value);
}
// Handle putAll(), cleanUp(), invalidate(), and invalidateAll() similarly
}
你也可以用 ForwardingLoadingCache
做同样的事情,就像上面的 .get()
你应该从 expiringCache
和 .put()
加载值到weakCache
在相关加载方法中。