I am having a Loading Cache like this :
MyCacheLoader loader=new MyCacheLoader();
MyRemovalListener listener=new MyRemovalListener();
LoadingCache<String, String> myCache = CacheBuilder.newBuilder()
.concurrencyLevel(10)
.weakKeys()
.maximumSize(2)
.expireAfterWrite(120, TimeUnit.SECONDS)
.removalListener(listener)
.build(loader);
But when I do something like this to test :
System.out.println(myCache.get("100"));
System.out.println(myCache.get("103"));
System.out.println(myCache.get("110"));
System.out.println(myCache).get("111"));
Thread.sleep(230000);
System.out.println(myCache.size());
Am still getting 2 and not zero. Why ? After more than 120 seconds I should have got zero size if am not wrong ?
MyCacheLoader
public class MyCacheLoader extends CacheLoader<String,String> {
@Override
public String load(String key) throws Exception {
return key;
}
}
MyRemovalListener
public class MyRemovalListener implements RemovalListener<String,String> {
Logger logger = LoggerFactory.getLogger(MyRemovalListener.class);
@Override
public void onRemoval(RemovalNotification<String, String> removalNotification) {
logger.info("Message with message Id ("+
removalNotification.getKey()+ ") is removed.");
System.out.println("Message with message Id ("+
removalNotification.getKey()+ ") is removed.");
}
}
First, if you are new to Guava's Cache API or if you are treating it as if it implements the Map<K, V> interface then I recommend reading CachesExplained · google/guava Wiki. "A Cache is similar to ConcurrentMap, but not quite the same."
e.g. Cache.size() "returns the approximate number of entries in this cache" (emphasis added) unlike Map.size() which "returns the number of key-value mappings in this map."
As such, we should not expect Cache.size() to return an exact number of entries but an approximate one. I would not generally make assertions on Cache.size() although I certainly would on Map.size().
Second, "caches built with CacheBuilder do not perform cleanup and evict values 'automatically,' or instantly after a value expires, or anything of the sort. Instead, it performs small amounts of maintenance during write operations, or during occasional read operations if writes are rare" (When Does Cleanup Happen? · CachesExplained · google/guava Wiki).
Consider the following example:
LoadingCache<String, String> myCache = CacheBuilder.newBuilder()
.concurrencyLevel(10)
.weakKeys()
.maximumSize(2)
.expireAfterWrite(120, TimeUnit.MILLISECONDS)
.removalListener(notification ->
System.out.println(notification.getKey() + " removed"))
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
System.out.println("loading " + key);
return UUID.randomUUID().toString();
}
});
myCache.get("100");
myCache.get("103");
myCache.get("110");
myCache.get("111");
Thread.sleep(230);
System.out.println(myCache.size());
myCache.get("111");
System.out.println(myCache.size());
Ouptut:
loading 100
loading 103
loading 110
100 removed
loading 111
103 removed
2
110 removed
111 removed
loading 111
1
As you can see, evictions here do not occur until items are read from the cache.
For more details along with a more detailed example see my answer to How does timed cache expiry work?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With