Understanding Guava's Caching Mechanisms: CacheBuilder and LoadingCache Tutorial
Guava provides a flexible caching API centered around the CacheBuilder, Cache, and LoadingCache classes that support automatic loading, size-based eviction, time-based expiration, and detailed statistics collection.
Google's Guava library offers sophisticated caching capabilities through its com.google.common.cache package, providing thread-safe, high-performance alternatives to manual map-based caching solutions. Understanding Guava's caching mechanisms enables developers to implement memory-efficient data layers with automatic eviction policies and loading strategies. This guide examines the core components and configuration options available in the google/guava repository.
Core Components of Guava's Caching
The caching framework revolves around three primary abstractions that work together to provide both manual and automatic caching behaviors.
CacheBuilder Configuration
Located in guava/src/com/google/common/cache/CacheBuilder.java, the CacheBuilder class implements the fluent builder pattern for constructing customized cache instances. This class provides methods to configure maximum size limits, expiration policies, reference types, and removal listeners before instantiating the final cache object. The builder returns either a LoadingCache when supplied with a CacheLoader instance, or a manual Cache instance when built without a loader.
Cache and LoadingCache Interfaces
The guava/src/com/google/common/cache/Cache.java file defines the base Cache interface, which provides fundamental operations including getIfPresent(), put(), invalidate(), and asMap(). For automatic value loading, guava/src/com/google/common/cache/LoadingCache.java extends Cache to add the get(K key) method, which automatically invokes the cache loader when a key is absent, and getAll(Iterable<? extends K> keys) for efficient bulk loading operations.
Key Caching Capabilities
Guava's caching mechanisms support multiple eviction strategies and monitoring features that address different memory management and performance requirements.
Size-Based and Weight-Based Eviction
Developers can enforce memory bounds using the maximumSize(long maximumSize) method in CacheBuilder, which triggers LRU (Least Recently Used) eviction when the cache exceeds the specified entry count. For scenarios where entries vary significantly in memory footprint, the weigher() method allows assigning custom weights to entries, working in conjunction with maximumWeight() to evict based on total weight rather than simple entry counts.
Time-Based Expiration Policies
The framework provides two distinct expiration mechanisms through CacheBuilder: expireAfterWrite(Duration duration) removes entries a fixed period after creation or last update, while expireAfterAccess(Duration duration) evicts entries that haven't been read within the specified timeframe. These policies execute automatically during write and read operations, ensuring stale data does not persist beyond configured time limits.
Reference-Based Eviction with Weak and Soft References
For memory-sensitive applications, CacheBuilder supports weakKeys(), weakValues(), and softValues() configurations that allow the garbage collector to reclaim cached entries. When enabled, the cache does not prevent GC collection of its keys or values, making this approach ideal for transient data that should not trigger OutOfMemoryError conditions. Note that soft references (softValues()) are generally preferred over weak references for values, as they resist collection longer under memory pressure.
Removal Listeners and Statistics Collection
The removalListener(RemovalListener<K, V> listener) method registers callbacks that receive RemovalNotification objects whenever entries are evicted or manually removed, enabling audit trails or cleanup operations. Performance monitoring is available through recordStats(), which instruments the cache to collect hit rates, miss counts, load times, and eviction statistics accessible via the CacheStats class defined in guava/src/com/google/common/cache/CacheStats.java.
Automatic Refresh Capabilities
The refreshAfterWrite(Duration duration) method configures asynchronous reloading of stale entries without blocking read operations. When an entry exceeds the refresh duration, subsequent reads return the existing value while triggering the CacheLoader to fetch updated data in the background, ensuring low latency under load while maintaining data freshness.
Practical Implementation Examples
The following examples demonstrate common configuration patterns using CacheBuilder and the associated interfaces.
Basic Loading Cache with Size and Time Limits
This example from guava/src/com/google/common/cache/ demonstrates a LoadingCache with automatic loading, size-based eviction, and expiration:
// Manual cache with size limit and expiration
LoadingCache<String, Graph> graphs = CacheBuilder.newBuilder()
.maximumSize(10_000) // size-based eviction
.expireAfterWrite(Duration.ofMinutes(10)) // time-based eviction
.removalListener((RemovalNotification<String, Graph> n) ->
System.out.println("Removed: " + n.getKey() + " because " + n.getCause()))
.recordStats() // enable statistics
.build(new CacheLoader<String, Graph>() {
@Override public Graph load(String key) throws Exception {
return createExpensiveGraph(key);
}
});
Cache with Weak References and Custom Ticker
For testing or specialized timing requirements, you can configure weak references and custom time sources:
// Cache with weak keys and a custom ticker (useful for testing)
Ticker fakeTicker = Ticker.systemTicker(); // replace with a mock for tests
Cache<String, String> cache = CacheBuilder.newBuilder()
.weakKeys() // keys are weakly referenced
.ticker(fakeTicker) // custom time source
.build();
cache.put("foo", "bar");
System.out.println(cache.getIfPresent("foo")); // prints "bar"
Summary
- Guava's caching mechanisms are implemented through
CacheBuilder,Cache, andLoadingCacheclasses located inguava/src/com/google/common/cache/. - Automatic loading is provided by implementing the
CacheLoaderabstract class and building aLoadingCacheviaCacheBuilder.build(loader). - Eviction policies include size-based (
maximumSize), weight-based (maximumWeightwithweigher), time-based (expireAfterWrite,expireAfterAccess), and reference-based (weakKeys,softValues) strategies. - Monitoring capabilities include removal listeners for eviction callbacks and statistics collection via
recordStats()to obtainCacheStatsmetrics. - Refresh functionality allows non-blocking background updates using
refreshAfterWrite()to maintain low latency while updating stale entries.
Frequently Asked Questions
What is the difference between Cache and LoadingCache in Guava?
Cache provides manual cache operations requiring explicit put() calls to populate entries, while LoadingCache automatically computes values using the CacheLoader specified during construction. When calling get(key) on a LoadingCache, the loader's load() method executes automatically if the key is absent, whereas Cache requires manual handling of missing entries or use of get(key, Callable).
How does Guava handle cache eviction when maximum size is reached?
When maximumSize() is configured and the cache exceeds the limit, Guava evicts the least recently used (LRU) entries until the size falls below the threshold. This eviction occurs during write operations and does not require a background thread, making it suitable for high-throughput environments without additional threading overhead.
Can I use weak or soft references in Guava caches?
Yes, CacheBuilder supports weakKeys(), weakValues(), and softValues() configurations that allow the garbage collector to reclaim cached entries when memory pressure occurs. Weak references are collected aggressively during GC cycles, while soft references persist longer and are typically collected only before OutOfMemoryError conditions, making them preferable for value caching.
How do I monitor cache performance in Guava?
Enable statistics collection by calling recordStats() during CacheBuilder configuration, then access metrics through Cache.stats(), which returns a CacheStats object. This object provides hit count, miss count, load success and exception counts, total load time, and eviction count, allowing precise measurement of cache efficiency and performance characteristics.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →