🧑 博主简介:CSDN博客专家历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程高并发设计Springboot和微服务,熟悉LinuxESXI虚拟化以及云原生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<>() {@Overridepublic void saveToDatabase(String key, User value) {jdbcTemplate.update("INSERT OR REPLACE INTO users (id, name) VALUES (?, ?)", key, value.getName());}@Overridepublic 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");

关键特性说明:

  1. 自动加载

    • 当调用 get() 方法且缓存未命中时,自动通过 DataLoader 从数据库加载
    • 加载成功后自动填充缓存
  2. 写穿透

    • put() 操作时:
      • 先通过 DataSynchronizer 保存到数据库
      • 再更新缓存
    • 保证数据库与缓存的数据一致性
  3. 删除同步

    • delete() 操作时:
      • 先删除数据库数据
      • 再使缓存失效
    • 缓存过期/淘汰时:
      • 通过 RemovalListener 自动触发数据库删除
  4. 缓存配置

    • 可自定义过期时间(expireAfterWrite
    • 可设置最大容量(maximumSize
    • 支持其他Caffeine特性(刷新策略、弱引用等)

关键特性对比表

功能配置方法适用场景
写入过期expireAfterWrite()数据更新频率低的场景
访问过期expireAfterAccess()读多写少的场景
自适应过期expireAfter(Expiry)需要动态过期时间的场景
数量淘汰maximumSize()通用场景
权重淘汰maximumWeight() + weigher()缓存对象大小差异大的场景
异步刷新refreshAfterWrite()高并发读取+后台更新
弱/软引用weakKeys()/softValues()内存敏感型应用

注意事项:

  1. 刷新 vs 过期

    • 刷新 (refreshAfterWrite) 异步更新旧值,不阻塞请求
    • 过期 (expireAfterWrite) 会阻塞请求直到新值加载完成
  2. 权重计算

    • 确保 weigher 计算快速(纳秒级)
    • 权重总和不超过 maximumWeight
  3. 过期时间精度

    • 默认时间精度≈1秒,需要毫秒级精度可配置:
    .scheduler(Scheduler.systemScheduler())
    
  4. 并发加载控制

    • 相同key并发请求时,只有一个线程执行加载
    • 可通过 executor() 指定自定义线程池

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91202.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91202.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/91202.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# _列表(List<T>)_ 字典(Dictionary<TKey, TValue>)

目录 列表&#xff08;List&#xff09;特点 创建列表 RemoveAll 删除与之条件相匹配的数据 会返回删除的个数 Capacity 获取或设置列表的容量 更多方法可参照上篇文章&#xff1a;C#_ArrayList动态数组 字典&#xff08;Dictionary&#xff09;特点 定义一个字典 向字…

【实时Linux实战系列】实时网络控制与调度

在实时控制系统中&#xff0c;网络调度是确保实时数据流传输和处理不受延迟影响的关键。实时网络控制与调度技术对于工业自动化、金融交易、多媒体流等领域至关重要。通过合理设计网络调度策略&#xff0c;可以显著提高系统的实时性和可靠性。本文将介绍如何在实时控制系统中实…

Qwen3-Coder:介绍及使用 -- 超强AI编程助手

更多内容&#xff1a;XiaoJ的知识星球 目录一、Qwen3-Coder模型介绍1.预训练阶段&#xff08;Pre-Training&#xff09;2.后训练阶段&#xff08;Post-Training&#xff09;1&#xff09;Scaling Code RL: Hard to Solve, Easy to Verify2&#xff09;Scaling Long-Horizon RL二…

uniapp 如果进入页面输入框自动聚焦,此时快速返回页面或者跳转到下一个页面,输入法顶上来的页面出现半屏的黑屏问题。

如果进入页面输入框自动聚焦&#xff0c;此时快速返回页面或者跳转到下一个页面&#xff0c;输入法顶上来的页面出现半屏的黑屏问题。输入法出来后&#xff0c;设置了自动将页面顶上来的配置&#xff1a;pages.json"softinputMode": "adjustResize""g…

深入了解 Kubernetes(k8s):从概念到实践

目录 一、k8s 核心概念 二、k8s 的优势 三、k8s 架构组件 控制平面组件 节点组件 四、k8s docker 运行前后端分离项目的例子 1. 准备前端项目 2. 准备后端项目 3. 创建 k8s 部署配置文件 4. 部署应用到 k8s 集群 在当今云计算和容器化技术飞速发展的时代&#xff0c…

Android User版本默认用test-keys,如何改用release-keys

Android User版本 默认用test-keys&#xff0c; 如何改用release-keys 开发云 - 一站式云服务平台 --- build/core/Makefile | 5 1 file changed, 5 insertions() diff --git a/build/core/Makefile b/build/core/Makefile index --- a/build/core/Makefile b/build/core…

从零开始学习Dify-数据库数据可视化(五)

概述上一篇文章我们围绕 Excel 文件展开数据可视化教学&#xff0c;逐步掌握了数据导入、图表构建和 AI 智能分析。在实际业务环境中&#xff0c;很多数据并不是保存在表格中&#xff0c;而是存储于数据库系统中&#xff0c;尤其是最常见的 MySQL。本篇作为本系列的第五篇&…

使用vue2和 element-ui 做一个点餐收银台系统前端静态项目

今天给大家分享一个 关于点餐收银台的静态网站&#xff0c;最近一直在练习前端项目&#xff0c;就使用vue2和 element-ui 做了一个 这样简单的 收银台系统。先给大家看一下 做出来的样子。 因为是练习项目 所以页面功能还是比较简单的。 使用的技术是&#xff1a; 技术栈 Vu…

Spring Boot自动配置原理深度解析

Spring Boot自动配置原理深度解析 一、自动配置核心概念 1.1 什么是自动配置 Spring Boot自动配置(Auto-Configuration)是其核心特性之一&#xff0c;能够根据项目依赖自动配置Spring应用程序。例如&#xff1a; 当检测到H2数据库依赖时&#xff0c;自动配置内存数据库当存在Sp…

关于 Apache Ignite 中 Job 调度(Job Scheduling)与冲突控制(Collision Control) 的机制说明

这段内容是关于 Apache Ignite 中 Job 调度&#xff08;Job Scheduling&#xff09;与冲突控制&#xff08;Collision Control&#xff09; 的机制说明。我来为你逐段解析&#xff0c;帮助你深入理解其原理和使用方式。&#x1f50d; 一、核心概念&#xff1a;Job 调度与 Colli…

网络资源模板--基于Android Studio 实现的课程管理App

目录 一、测试环境说明 二、项目简介 三、项目演示 四、部设计详情&#xff08;部分) 登录页 首页 五、项目源码 一、测试环境说明 电脑环境 Windows 11 编写语言 JAVA 开发软件 Android Studio (2020) 开发软件只要大于等于测试版本即可(近几年官网直接下载也可…

ROUGE-WE:词向量化革新的文本生成评估框架

一、ROUGE 基础与核心局限 ROUGE&#xff08;Recall-Oriented Understudy for Gisting Evaluation&#xff09; 是自动文本摘要与机器翻译的主流评估指标&#xff0c;由 Chin-Yew Lin 在2004年发表的论文中首次系统提出。其核心变体包括&#xff1a; ROUGE-N&#xff1a;基于…

MGER综合实验

一.拓扑二、实验需求 1、R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;其所有地址均配为公有IP地址; 2、R1和R5间使用PPP的PAP认证&#xff0c;R5为主认证方; R2与R5之间使用ppp的CHAP认证&#xff0c;R5为主认证方; R3与R5之间使用HDLC封装; 3、R1、R2、R3构建一个MGRE环…

高可用集群Keepalived、Redis、NoSQL数据库Redis基础管理

1. 总结负载均衡常见的算法 轮询 (Round Robin)&#xff1a;按顺序将请求依次分配给后端服务器&#xff0c;适合服务器性能相近的场景。 加权轮询 (Weighted Round Robin)&#xff1a;在轮询的基础上&#xff0c;根据服务器的权重分配请求。 随机 (Random)&#xff1a;随机选…

【深度学习】独热编码(One-Hot Encoding)

独热编码&#xff08;One-Hot Encoding&#xff09; 在机器学习中&#xff0c;数据预处理是不可或缺的关键一步。面对各种非数值类型的分类数据&#xff08;Categorical Data&#xff09;&#xff0c;如何将其转换为机器学习模型能够“理解”的语言呢&#xff1f;独热编码&…

Promise完全体总结

我们在上篇文章提到了异步会导致无法通过返回值来获取函数的执行结果&#xff0c;我们通过传入一个回调函数的方式&#xff0c;以参数的形式获取到了我们想要获取的数据&#xff0c;但是这样如果需要对数据进行多次操作导致形成回调地狱那种不便于阅读以及护理的代码。为了解决…

SpringJDBC源码初探-DataSource类

一、DataSource接口核心作用 DataSource是JDBC规范的核心接口&#xff0c;位于javax.sql包中&#xff0c;用于替代传统的DriverManager获取数据库连接。Spring框架通过org.springframework.jdbc.datasource包对该接口进行了增强&#xff0c;提供连接池管理、事务绑定等高级特性…

C语言(08)——关于指针(逐渐清晰版)

为了更好地理解本篇文章的知识内容&#xff0c;读者可以将以下文章作为补充知识进行阅读 &#xff1a; C语言————原码 补码 反码 &#xff08;超绝详细解释&#xff09;-CSDN博客 C语言————二、八、十、十六进制的相互转换-CSDN博客 C语言————斐波那契数列的理解…

LeetCode 1616.分割两个字符串得到回文串

给你两个字符串 a 和 b &#xff0c;它们长度相同。请你选择一个下标&#xff0c;将两个字符串都在 相同的下标 分割开。由 a 可以得到两个字符串&#xff1a; aprefix 和 asuffix &#xff0c;满足 a aprefix asuffix &#xff0c;同理&#xff0c;由 b 可以得到两个字符串 …

算法【1】

网址&#xff1a;主站 工具补充 1. sort 函数的使用规则 作用&#xff1a;对容器元素进行排序&#xff0c;默认升序。语法&#xff1a;sort(起始迭代器, 结束迭代器, 比较规则) 前两个参数是排序范围&#xff1a;[begin, end)&#xff08;包含begin&#xff0c;不包含end&am…