0

我想做这样的事情:

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

我期望的行为是,只有在未引用该值并且过期时间已过时,条目才会过期。这就是这种用法的工作方式吗?

4

2 回答 2

3

不是直接的,因为一旦没有对对象的强引用,弱值就会被垃圾回收。但是,您可以做的是使用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
}

你也可以用 a 做同样的事情ForwardingLoadingCache,就像.get()上面一样,你应该从相关的加载方法中将值expiringCache.put()weakCache加载到相关的加载方法中。

于 2016-05-31T22:28:12.247 回答
1

不,如果未引用该值或过期时间已过,则条目将过期:

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
于 2016-05-31T21:39:29.427 回答