Class Cache<K,V>
A bounded, process-local application cache: entries limited by count or by weight, expiring after a write, after an access or at a time each entry chooses, loaded at most once per key however many callers ask together.
private static final Cache<String, Price> PRICES = Cache.<String, Price>builder("prices")
.maximumSize(10000)
.expireAfterWriteMillis(60000)
.build();
...
Price p = PRICES.get(sku, new Cache.Loader<String, Price>() {
public Price load(String key) throws Exception {
return priceService.lookup(key);
}
});
Loading
get(Object, Loader) answers a live entry, or runs the loader on the
calling thread with no lock held. A second caller asking for the same key
while that load runs does not load again: it waits for the first one and
gets its result -- the value, or the same failure. A loader that fails, or
answers null, leaves the cache as it was; nothing is stored, so the next
caller loads again. A key invalidated or put(K, V) while its load is running
keeps what that call did: the loaded value is handed to the callers that
waited for it and is not stored over the newer state.
A loader may use the cache, but not for the key it is loading; that would
wait for itself, and is refused with IllegalStateException.
A waiting virtual thread naps rather than blocking its host, so a slow load holds back only the requests that want its key.
Eviction and expiry
Above the size or weight bound the least recently used entries go first.
An expired entry is never answered; it is removed, with an EXPIRED
notification, when a read finds it, when a write's periodic sweep does,
or on cleanUp(). size() cleans up first, so it counts only live
entries.
Removal notifications
The Cache.RemovalListener runs on the thread whose call removed the entry,
after the cache's lock is released, so it may use the cache. One that
throws is reported on standard error and does not affect the cache or the
call that triggered it. Notifications from one call are delivered in the
order the entries were removed.
Metrics
Every cache records cache.<name>.hits, .misses, .loads,
.load_failures and .evictions (counters), .size and .weight
(gauges) and .load.duration (a histogram, milliseconds) in
Metrics; the same figures are on the cache's own accessors. Two caches
built with one name share the counters, and the gauges read the newer.
Scope and cost
A cache lives in this process only: two instances of a server each hold their own, and nothing is shared or invalidated between them. Values are held by reference, so a value a caller changes changes for every reader. Each entry costs about a hundred bytes beyond its key and value -- a hash map entry with its access-order links, and a node holding the value, its weight and three timestamps -- on the JVM and in the native binary alike.
Server code: this class is not available in the app.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classA cache's settings.static interfaceWhere the cache reads the time: monotonic milliseconds.static interfaceA lifetime chosen per entry, from when it is written.static interfaceComputes the value for a key that is absent.static final classThrown byget(Object, Loader)when the loader threw a checked exception, which is its cause.static interfaceTold about every entry that leaves the cache.static interfaceThe weight of an entry, forCache.Builder.maximumWeight. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intIts lifetime ran out.static final intRemoved byinvalidate(K)orinvalidateAll().static final intOverwritten byput(K, V)or by a load.static final intEvicted to stay within the size or weight bound. -
Method Summary
Modifier and TypeMethodDescriptionstatic <K,V> Cache.Builder <K, V> A cache namedname; the name prefixes its metrics.voidcleanUp()Removes every expired entry now.longEntries evicted for size or weight; expiry and invalidation not counted.get(K key, Cache.Loader<K, V> loader) The live value forkey, loading it withloaderwhen absent.getIfPresent(K key) The live value forkey, or null.getName()longhitCount()voidinvalidate(K key) Removeskey, and keeps a load of it already running from storing its result.voidRemoves every entry, asinvalidate(K)does each.longLoads that completed, with a value or with null.longlongvoidStoresvalue, replacing what is there.longsize()Live entries, after acleanUp().longweight()The total weight of the entries: their count when no weigher is set.
-
Field Details
-
EXPLICIT
-
REPLACED
-
EXPIRED
public static final int EXPIREDIts lifetime ran out.- See Also:
-
SIZE
public static final int SIZEEvicted to stay within the size or weight bound.- See Also:
-
-
Method Details
-
builder
A cache namedname; the name prefixes its metrics. -
getName
-
getIfPresent
-
get
The live value forkey, loading it withloaderwhen absent. See the class description for concurrent callers, failures and null. -
put
-
invalidate
Removeskey, and keeps a load of it already running from storing its result. -
invalidateAll
public void invalidateAll()Removes every entry, asinvalidate(K)does each. -
cleanUp
public void cleanUp()Removes every expired entry now. -
size
public long size()Live entries, after acleanUp(). -
weight
public long weight()The total weight of the entries: their count when no weigher is set. -
hitCount
public long hitCount() -
missCount
public long missCount() -
loadCount
public long loadCount()Loads that completed, with a value or with null. -
loadFailureCount
public long loadFailureCount() -
evictionCount
public long evictionCount()Entries evicted for size or weight; expiry and invalidation not counted.
-