2016-05-31 10 views
0

Ich möchte so etwas wie dies zu tun:Können weakValues ​​() und expireAfterAccess() kombiniert werden?

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

Das Verhalten Ich gehe davon aus, dass ein Eintrag nur abgelaufen, wenn der Wert nicht und der Ablaufzeit verwiesen wird, verstrichen ist. Funktioniert das so?

Antwort

2

Nicht direkt, da der schwache Wert Müll sein kann gesammelt sobald es keine starken Verweise mehr auf das Objekt gibt. Sie können jedoch einen ForwardingCache verwenden, der durch zwei separate Caches, einen Puffer mit schwachem Wert und einen Cache mit zeitgesteuertem Ablauf unterstützt wird, so dass der zeitbasierte Cache einen starken Verweis auf das Objekt enthält und somit im Cache mit schwachem Wert bleibt . Es würde wie folgt aussehen:

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 
} 

Sie können mit einem ForwardingLoadingCache auch das gleiche tun, so wie .get() oben sollten Sie den Wert aus dem expiringCache und .put() in die weakCache in den entsprechenden Lademethoden laden .

+0

Vielen Dank! Das ist perfekt. Und du hast in meine Frage gesehen, dass ich meinte, dass es keine weiteren Verweise auf den Wert BESIDES des Caches geben sollte. Ich hatte nicht gedacht, dass eine schwache Referenz gc niemals verhindern wird. – jacob

1

Nein, erfolgt ein Eintrag verfallen, wenn der Wert nicht referenziert oder die Ablaufzeit verstrichen ist:

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

Vielen Dank! – jacob