Caffeine 缓存库的常用功能使用介绍_caffeine使用弱引用
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,
15年
工作经验,精通Java编程
,高并发设计
,Springboot和微服务
,熟悉Linux
,ESXI虚拟化
以及云原生Docker和K8s
,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作请加本人wx(注明来自csdn):foreast_sea
Caffeine 缓存库的常用功能使用介绍
文章目录
- Caffeine 缓存库的常用功能使用介绍
-
-
- 一、基础缓存操作
- 二、自动加载缓存(推荐)
- 三、过期策略配置
-
- 1. 全局过期策略
- 2. 单Key过期(高级用法)
- 四、淘汰策略配置
- 五、刷新策略(优于纯过期)
- 六、监听器与统计
- 七、异步操作
- 八、最佳实践配置模板
- 九、基于Caffeine实现的动态缓存
- 关键特性说明:
- 关键特性对比表
- 注意事项:
-
Caffeine
作为新一代高性能Java缓存库,在并发场景下展现出卓越表现。它通过创新的W-TinyLFU
淘汰算法实现高达99%
的命中率,并采用无锁设计使吞吐量较传统方案提升5-10
倍。该库提供灵活的缓存管理能力:支持基于时间(写入/访问过期)、数量或权重的淘汰策略;允许为单个Key设置专属过期时间;独创的异步刷新机制能在不阻塞请求的情况下更新数据。开发者可通过简洁的链式API配置内存控制、加载逻辑和事件监听,轻松构建高并发低延迟的智能缓存系统。其与Guava Cache
兼容的接口设计,更使迁移成本降至最低。
以下是 Caffeine 缓存库的常用功能使用介绍,涵盖基础操作、过期策略、淘汰配置等核心功能:
一、基础缓存操作
import com.github.benmanes.caffeine.cache.Cache;import com.github.benmanes.caffeine.cache.Caffeine;// 1. 创建缓存实例Cache<String, Object> cache = Caffeine.newBuilder() .build();// 2. 添加数据cache.put(\"key1\", \"value1\");// 3. 获取数据(手动)Object value = cache.getIfPresent(\"key1\"); // 存在返回value,否则null// 4. 删除数据cache.invalidate(\"key1\");cache.invalidateAll(); // 清空缓存
二、自动加载缓存(推荐)
LoadingCache<String, Object> cache = Caffeine.newBuilder() .build(key -> { // 缓存未命中时自动执行的加载逻辑 return fetchFromDB(key); // 自定义数据库加载方法 });// 自动加载数据(缓存未命中时执行build中的逻辑)Object value = cache.get(\"user_123\");
三、过期策略配置
1. 全局过期策略
Cache<String, Object> cache = Caffeine.newBuilder() // 写入后30分钟过期 .expireAfterWrite(30, TimeUnit.MINUTES) // 最后访问后15分钟过期 .expireAfterAccess(15, TimeUnit.MINUTES) // 自定义过期策略(按需实现) .expireAfter(new Expiry<String, Object>() { public long expireAfterCreate(String key, Object value, long currentTime) { return TimeUnit.MINUTES.toNanos(10); // 创建后10分钟过期 } public long expireAfterUpdate(String key, Object value, long currentTime, long currentDuration) { return currentDuration; // 更新后不改变过期时间 } public long expireAfterRead(String key, Object value, long currentTime, long currentDuration) { return currentDuration; // 读取后不改变过期时间 } }) .build();
2. 单Key过期(高级用法)
// 创建支持变长过期的缓存Cache<String, Object> cache = Caffeine.newBuilder() .expireAfter(new Expiry<String, Object>() { // ...实现同上 }) .build();// 为特定Key设置不同过期时间cache.policy().expireVariably().ifPresent(policy -> { policy.put(\"hot_key\", \"value\", 2, TimeUnit.HOURS); // 2小时 policy.put(\"cold_key\", \"value\", 10, TimeUnit.MINUTES); // 10分钟});
四、淘汰策略配置
Cache<String, Object> cache = Caffeine.newBuilder() // 基于数量淘汰(最多1000个条目) .maximumSize(1000) // 基于权重淘汰(需实现Weigher) .maximumWeight(10_000) .weigher((String key, Object value) -> { // 自定义权重计算逻辑 if (value instanceof String) return ((String) value).length(); if (value instanceof List) return ((List<?>) value).size(); return 1; }) // 基于引用回收(谨慎使用) .weakKeys() // 弱引用Key .weakValues() // 弱引用Value .softValues() // 软引用Value .build();
五、刷新策略(优于纯过期)
LoadingCache<String, Object> cache = Caffeine.newBuilder() // 写入后1分钟可刷新(不阻塞读取,异步刷新旧值) .refreshAfterWrite(1, TimeUnit.MINUTES) .build(key -> fetchFromDB(key));
六、监听器与统计
Cache<String, Object> cache = Caffeine.newBuilder() // 移除监听器 .removalListener((String key, Object value, RemovalCause cause) -> { System.out.printf(\"Key %s was removed (%s)%n\", key, cause); }) // 启用统计 .recordStats() .build();// 获取统计信息CacheStats stats = cache.stats();System.out.printf(\"Hit Rate: %.2f%%, Loads: %d%n\", stats.hitRate() * 100, stats.loadCount());
七、异步操作
// 1. 异步缓存AsyncLoadingCache<String, Object> asyncCache = Caffeine.newBuilder() .buildAsync(key -> fetchFromDB(key));// 获取数据(返回CompletableFuture)CompletableFuture<Object> future = asyncCache.get(\"key1\");// 2. 同步视图操作Object value = asyncCache.synchronous().get(\"key1\");
八、最佳实践配置模板
LoadingCache<String, Object> optimalCache = Caffeine.newBuilder() // 容量控制 .maximumSize(10_000) // 过期策略 .expireAfterWrite(30, TimeUnit.MINUTES) // 刷新策略 .refreshAfterWrite(5, TimeUnit.MINUTES) // 统计和监听 .recordStats() .removalListener((key, value, cause) -> logRemoval(key, cause)) // 自动加载 .build(key -> fetchFromDB(key));
九、基于Caffeine实现的动态缓存
我们有时候需要这样一种场景:当用户请求某个key的时候,该缓存自动从数据库去加载,就是注册一个数据库加载器(自己实现),当获取不到该key时,自动走数据库查询,然后存入该key中。当往caffeine缓存中插入一个key后,如果缓存没有,则自动存入,并自动同步到数据库中,当删除一个key,或key过期后,自动从数据库同步删除。
以下是简单的实现流程:
import com.github.benmanes.caffeine.cache.*;import java.util.concurrent.TimeUnit;public class DynamicCache<K, V> { private final Cache<K, V> cache; private final DataLoader<K, V> dataLoader; private final DataSynchronizer<K, V> dataSynchronizer; public DynamicCache(DataLoader<K, V> dataLoader, DataSynchronizer<K, V> dataSynchronizer) { this.dataLoader = dataLoader; this.dataSynchronizer = dataSynchronizer; this.cache = Caffeine.newBuilder() // 配置缓存策略(按需设置) .expireAfterWrite(30, TimeUnit.MINUTES) // 30分钟过期 .maximumSize(1000)// 最大缓存项 // 注册移除监听器(用于删除数据库数据) .removalListener((K key, V value, RemovalCause cause) -> { if (cause.wasEvicted()) { // 仅处理过期或容量剔除 dataSynchronizer.deleteFromDatabase(key); } }) // 注册加载器(用于缓存未命中时从DB加载) .build(key -> { V value = dataLoader.loadFromDatabase(key); if (value == null) throw new Exception(\"Key not found\"); return value; }); } // 获取数据(自动加载) public V get(K key) { return cache.get(key, k -> { V value = dataLoader.loadFromDatabase(k); if (value == null) throw new RuntimeException(\"Data not found\"); return value; }); } // 添加/更新数据(同步到数据库) public void put(K key, V value) { // 先同步到数据库 dataSynchronizer.saveToDatabase(key, value); // 再更新缓存 cache.put(key, value); } // 删除数据(同步删除数据库) public void delete(K key) { // 先删除数据库数据 dataSynchronizer.deleteFromDatabase(key); // 再使缓存失效 cache.invalidate(key); } // 数据库加载器接口 public interface DataLoader<K, V> { V loadFromDatabase(K key); } // 数据库同步器接口 public interface DataSynchronizer<K, V> { void saveToDatabase(K key, V value); void deleteFromDatabase(K key); }}
上述接口使用示例:
// 1. 实现数据库操作接口DynamicCache.DataLoader<String, User> loader = key -> jdbcTemplate.queryForObject(\"SELECT * FROM users WHERE id=?\", User.class, key);DynamicCache.DataSynchronizer<String, User> synchronizer = new DynamicCache.DataSynchronizer<>() { @Override public void saveToDatabase(String key, User value) { jdbcTemplate.update(\"INSERT OR REPLACE INTO users (id, name) VALUES (?, ?)\", key, value.getName()); } @Override public void deleteFromDatabase(String key) { jdbcTemplate.update(\"DELETE FROM users WHERE id=?\", key); }};// 2. 创建缓存实例DynamicCache<String, User> userCache = new DynamicCache<>(loader, synchronizer);// 3. 使用缓存// 自动加载(缓存未命中时从DB加载)User user = userCache.get(\"user123\"); // 添加/更新(同步到DB)userCache.put(\"user456\", new User(\"Alice\"));// 删除(同步删除DB数据)userCache.delete(\"user789\");
关键特性说明:
-
自动加载:
- 当调用
get()
方法且缓存未命中时,自动通过DataLoader
从数据库加载 - 加载成功后自动填充缓存
- 当调用
-
写穿透:
put()
操作时:- 先通过
DataSynchronizer
保存到数据库 - 再更新缓存
- 先通过
- 保证数据库与缓存的数据一致性
-
删除同步:
delete()
操作时:- 先删除数据库数据
- 再使缓存失效
- 缓存过期/淘汰时:
- 通过 RemovalListener 自动触发数据库删除
-
缓存配置:
- 可自定义过期时间(
expireAfterWrite
) - 可设置最大容量(
maximumSize
) - 支持其他Caffeine特性(刷新策略、弱引用等)
- 可自定义过期时间(
关键特性对比表
expireAfterWrite()
expireAfterAccess()
expireAfter(Expiry)
maximumSize()
maximumWeight()
+ weigher()
refreshAfterWrite()
weakKeys()
/softValues()
注意事项:
-
刷新 vs 过期:
- 刷新 (
refreshAfterWrite
) 异步更新旧值,不阻塞请求 - 过期 (
expireAfterWrite
) 会阻塞请求直到新值加载完成
- 刷新 (
-
权重计算:
- 确保
weigher
计算快速(纳秒级) - 权重总和不超过
maximumWeight
- 确保
-
过期时间精度:
- 默认时间精度≈1秒,需要毫秒级精度可配置:
.scheduler(Scheduler.systemScheduler())
-
并发加载控制:
- 相同key并发请求时,只有一个线程执行加载
- 可通过
executor()
指定自定义线程池