weakValues()和expireAfterAccess()可以结合使用吗?

问题描述:

我想要做这样的事情:weakValues()和expireAfterAccess()可以结合使用吗?

CacheBuilder 
      .newBuilder() 
      .maximumSize(CONFIG.cacheMaxSize()) 
      .expireAfterAccess(CONFIG.cacheTimeout(), 
           CONFIG.cacheTimeUnit()) 
      .weakValues() 
      .build(cacheLoader); 

我期望的行为是一个条目将仅值未引用和有效期已过到期。这是怎么用的?

不是直接的,因为弱者值可以被垃圾收集只要没有更强烈的对象引用。然而,你可以做的是使用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在相关的装载方法。

+0

谢谢!那很完美。你看到我的问题,我的意思是应该没有其他引用的价值BESIDES缓存。我没有想过,一个弱引用不会阻止gc。 – jacob

没有,一个条目将到期,如果该值不引用或到期时间已经过去了:

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"; 
    } 
} 

Ouptut:

java.lang.AssertionError: reference did not prevent expiration 
+0

非常感谢! – jacob