GuavaCache RemovalListener 失效

本文探讨了在使用 GuavaCache 时遇到的失效监听(RemovalListener)未触发的问题。当期望在缓存条目过期后自动执行回调时,发现只有手动调用 `invalidate(key)` 才会触发。研究后发现,GuavaCache 不保证过期即删除,而是会在访问已过期的 Key 时才会检查并移除,导致回调不触发。这一设计是为了避免持续维护缓存导致的资源竞争和线程创建限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题

最近接触到 Google 的 Java 工具包 Guava,确实很好用,特别是其中的 GuavaCache 算是经常使用到的本地缓存,这次遇到一个需求是希望在 xxx min 之后做一个延时操作,虽然可以开一个定时任务做,但是由于当时代码里正好使用到了 GuavaCache,想起来可以基于 Key 的过期做一个回调方法不就行了嘛,猜测 GuavaCache 肯定是支持这样的回调 API 的,一查果然如此。

于是乎,代码写得很快,如下:

private static class MyRemovalListener implements RemovalListener<Integer, Integer> {
   
     
    @Override  
    public void onRemoval(RemovalNotification<Integer, Integer> notification) {  
        doSomething();
    }  
}  

### Guava Cache 本地缓存的使用方法 Guava Cache 是 Google 提供的一个高性能本地缓存库,适用于需要高并发读写、缓存大小有限、允许数据短暂不一致的场景。其设计灵感来源于 `ConcurrentHashMap`,具备线程安全特性,并支持多种缓存清理策略,如基于大小、时间或引用强度等。 #### 创建缓存对象 Guava 使用 `CacheBuilder` 类来构建缓存实例,采用建造者模式进行配置。通过链式调用设置缓存的最大容量、过期时间、并发级别等参数: ```java import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; public class GuavaCacheExample { private static final Cache<String, String> cache = CacheBuilder.newBuilder() .maximumSize(100) // 设置最大缓存条目数 .expireAfterWrite(10, TimeUnit.MINUTES) // 写入后10分钟过期 .build(); } ``` 该方式创建的缓存对象默认不会自动加载数据,若需在 key 不存在时自动计算值,可以结合 `CacheLoader` 实现: ```java import com.google.common.cache.CacheLoader; private static final Cache<String, String> cacheWithLoader = CacheBuilder.newBuilder() .maximumSize(50) .build(new CacheLoader<String, String>() { @Override public String load(String key) { return "default-" + key; // 当key不存在时返回默认值 } }); ``` #### 缓存的基本操作 Guava Cache 支持常见的缓存操作,包括插入、获取、删除等: - **插入数据**:使用 `put(key, value)` 方法手动插入键值对。 - **获取数据**:使用 `getIfPresent(key)` 获取已存在的值,或 `get(key)` 结合 `CacheLoader` 自动加载。 - **删除数据**:调用 `invalidate(key)` 删除指定键的缓存项;`invalidateAll()` 清除全部缓存。 - **统计信息**:通过 `cache.stats()` 获取缓存命中率、加载次数等统计信息。 示例代码如下: ```java // 插入缓存 cache.put("user:1001", "Alice"); // 获取缓存(存在则返回,否则为 null) String user = cache.getIfPresent("user:1001"); // 获取缓存并自动加载(当 key 不存在时触发 CacheLoader) String loadedUser = cacheWithLoader.getUnchecked("user:1002"); // 删除缓存 cache.invalidate("user:1001"); ``` #### 缓存失效策略 Guava Cache 支持以下几种缓存失效机制: - **基于大小**:通过 `maximumSize(long size)` 设置最大缓存条目数,超过后根据最近最少使用(LRU)策略清除旧条目。 - **基于时间**:通过 `expireAfterWrite(long duration, TimeUnit unit)` 或 `expireAfterAccess(long duration, TimeUnit unit)` 设置写入或访问后的存活时间。 - **基于引用强度**:通过 `weakKeys()` 或 `softValues()` 配置键值的垃圾回收策略,适合内存敏感型应用[^3]。 #### 异步刷新与监听器 Guava Cache 还支持异步刷新机制和缓存事件监听: - **刷新机制**:使用 `refresh(key)` 方法可异步重新加载缓存值,适用于缓存仍可用但需更新的场景。 - **监听器**:通过 `removalListener(RemovalListener<? super K, ? super V> listener)` 添加缓存移除监听器,用于记录日志、统计或清理资源。 ```java import com.google.common.cache.RemovalListener; import com.google.common.cache.RemovalNotification; RemovalListener<String, String> removalListener = new RemovalListener<>() { public void onRemoval(RemovalNotification<String, String> notification) { System.out.println("Removed key: " + notification.getKey() + ", value: " + notification.getValue()); } }; private static final Cache<String, String> cacheWithListener = CacheBuilder.newBuilder() .maximumSize(100) .removalListener(removalListener) .build(); ``` --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值